{"id":16098964,"url":"https://github.com/hellerve/mimir","last_synced_at":"2025-10-26T06:37:38.789Z","repository":{"id":79626333,"uuid":"67718315","full_name":"hellerve/mimir","owner":"hellerve","description":"Mimir is the God of Wisdom","archived":false,"fork":false,"pushed_at":"2016-10-24T13:39:32.000Z","size":25,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-10T23:13:43.895Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hellerve.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-09-08T15:58:57.000Z","updated_at":"2023-10-02T12:27:47.000Z","dependencies_parsed_at":"2023-05-14T02:45:34.366Z","dependency_job_id":null,"html_url":"https://github.com/hellerve/mimir","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/hellerve/mimir","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellerve%2Fmimir","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellerve%2Fmimir/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellerve%2Fmimir/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellerve%2Fmimir/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hellerve","download_url":"https://codeload.github.com/hellerve/mimir/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hellerve%2Fmimir/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281068936,"owners_count":26438554,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-26T02:00:06.575Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-09T18:25:14.604Z","updated_at":"2025-10-26T06:37:38.758Z","avatar_url":"https://github.com/hellerve.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mimir\n\nMany a foe of the Allfather fell prey to he cunning wisdom of Mímir.\n\u003cbr/\u003e\nThe One-eyed One himself sacrificed his body to the will of the All-Knowing,\n\u003cbr/\u003e\nfor wisdom is greater than what is carnal.\n\nAnd so we submit to the Great and Powerful in the pursuit of that\nwhich is true.\n\n## (mimir:connect zepto databases)\n\nThis library aims to be a database wrapper that brings its own\nlittle DSL. It currently only works with PostgreSQL, MySQL, and\nSqlite and it is not done yet. Nonetheless, I release it to the\nworld right now as a RFC.\n\n## Installation\n\n```\nzeps install hellerve/mimir\n```\n\n## Usage\n\nmimir exposes functions that allow for connecting to and disconnecting\nfrom databases, and executing statements.\n\n```clojure\n(load \"mimir\")\n(import-all \"mimir\")\n\n; connect takes a hashmap that contains the keyvValue pairs as described in\n; https://www.postgresql.org/docs/8.1/static/libpq.html#LIBPQ-CONNECT\n(define conn (mimir:connect #{\"host\" \"127.0.0.1\" \"port\" \"5432\" \"dbname\" \"mydb\"}))\n\n; alternatively, you can specify a config file\n(define conn (mimir:connect-from-config \"tests/conf.zp\"))\n(mimir:connection? conn) ; =\u003e true\n\n; you can query the connection for a bit of information\n; it is always of this form\n(mimir:connection-info conn) ; =\u003e #{:driver \"somedriver\" :server-version \"0.1.0\"\n                             ;      :client-version \"0.1.0\" :transaction-support #t}\n```\n\nAfter a connection has been obtained, statements can be executed.\n\n```clojure\n(mimir:get-tables conn) ; will return a list of tables currently visible\n(mimir:execute conn \"select * from my-table\") ; will return a list of rows\n\n; we can also interpolate values into the statement.\n; Question marks will be replaced by the values found in the list\n(mimir:execute conn \"insert into my-table (id) values (?)\" [12])\n```\n\nAfter we're done (especially updating the DB), we should commit using\n`mimir:commit` to ensure the results are written to the database.\n\n**NOTE: For now the transactions are autocomitted. This might change\nin the future, so commiting it anyway is probably a good idea.**\n\n```clojure\n(mimir:commit conn) ; =\u003e nil\n```\n\nIf something goes wrong and the pending transactions cannot complete\n(only supported on backends that support transactions), we can rollback\nthe current commit.\n\n```clojure\n(mimir:rollback conn) ; =\u003e nil\n```\n\nIf we do not need the connection anymore, it is recommended to call\n`mimir:disconnect` for it to garbage-collect. The connection should\nnot be used anymore after that.\n\n```clojure\n(mimir:disconnect conn)\n```\n\nTo simplify things, mimir provides an abstraction called `mimir:with-connection`.\nIt will take either a connection object or a file path and a function in which\nto use the connection. It will be created for the function to use and the results\nof the function will be automatically commited, so that the user does not have to\nbother with that any more.\n\n```clojure\n(mimir:with-connection \"tests/conf.zp\"\n  (lambda (conn)\n    (write (mimir:execute conn \"select * from my-table\"))))\n```\n\n### The DSL\n\nThe DSL is a thin functional layer over SQL that makes working with databases\na bit less string-heavy and compositional.\n\nThe DSL lives in the `mimsql` namespace. It is self-contained and does not depend\non the rest of mimir in any way.\n\nFirst, we might want to define the entites we use.\n\n```clojure\n(load \"mimir/mimsql\")\n(import-all \"mimsql\" \"s\")\n\n; Entity definition follows the definition:\n; (s:entity \u003ctablename:atom\u003e \u003cfelds and reationships:mimsql types\u003e)\n; Fields are required, relationships are optional; order does not matter.\n(define user\n  (s:entity :user\n    (s:fields :id :group_id :username :firstname :lastname :password)))\n\n(define group\n  (s:entity :group\n    (s:fields :id :group_name)\n    (s:has-many user)))\n```\n\nOnce we have defined the entites and their relationships (`has-many`, `has-one`,\nand `belongs-to` are currently supported), we can query them. All of the functions\nemit mimsql types that implement the stringify protocol. Stringification turns\nthem into SQL queries.\n\n```clojure\n(s:select user)\n; =\u003e SELECT id, group_id username, firstname, lastname, password FROM users\n(s:select user :id)\n; =\u003e SELECT id FROM users\n(s:select group (s:with user))\n; =\u003e SELECT id, group_name FROM group JOIN user ON user.id=group_id\n```\n\nAs the last line showcases, the default join value is via the ID; you can\nspecify a join column (or a pair of columns), though.\n\n```clojure\n(s:select group :group_name (s:with user [:name :group_name]))\n; =\u003e SELECT group_name FROM group JOIN user ON user.name=group_name\n```\n\nThere are a few more advanced queries and filters, such as `ORDER BY` (`s:order`),\n`HAVING` (`s:having`), `LIMIT` (`s:limit`), `OFFSET` (`s:offset`), `WHERE`(`s:where`),\nsubqueries (`s:sub`) and raw joins (on tables that are not entites).\n\nLet's see that in action then.\n\n```clojure\n(s:select user\n  (s:where :id [\u003e 10])\n  (s:limit 10)\n  (s:order :id :desc)\n  (s:having :count :followers [\u003e 100])\n  (s:join :group [:id :group_id]))\n; =\u003e SELECT id, group_id, username, firstname, lastname, password FROM users\n;      WHERE id \u003e 10\n;      LIMIT 10\n;      ORDER BY id DESC\n;      HAVING count(followers) \u003e 100\n;      JOIN group ON group.id=group_id\n```\n\nNow for the big caveat emptor: this is really fresh, naive, and probably broken.\nI have yet to test this in a real world setting.\n\nI hope you like it anyway.\n\n\u003chr/\u003e\nHave fun!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhellerve%2Fmimir","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhellerve%2Fmimir","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhellerve%2Fmimir/lists"}