{"id":17156305,"url":"https://github.com/ashercn97/ormlette","last_synced_at":"2025-04-13T13:31:13.606Z","repository":{"id":257822096,"uuid":"870303812","full_name":"ashercn97/ormlette","owner":"ashercn97","description":"Ormlette is a delightful ORM (?) for Gleam!","archived":false,"fork":false,"pushed_at":"2024-10-13T22:07:02.000Z","size":65,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-24T03:07:49.725Z","etag":null,"topics":["beam","database","db","elixir","erlang","frm","functional-programming","gleam","gleam-lang","gleamlang","object-relational-mapping","orm","pgo","postgre","postgres","postgresql","sql"],"latest_commit_sha":null,"homepage":"","language":"Gleam","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/ashercn97.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":"2024-10-09T19:49:38.000Z","updated_at":"2024-10-21T03:03:04.000Z","dependencies_parsed_at":null,"dependency_job_id":"3704f44d-ae58-489e-80ab-528c34f7cfd9","html_url":"https://github.com/ashercn97/ormlette","commit_stats":{"total_commits":25,"total_committers":1,"mean_commits":25.0,"dds":0.0,"last_synced_commit":"6b87bc35b868ab0876715bce7a3d5a530b7c4bc3"},"previous_names":["ashercn97/ormlette"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashercn97%2Formlette","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashercn97%2Formlette/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashercn97%2Formlette/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashercn97%2Formlette/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ashercn97","download_url":"https://codeload.github.com/ashercn97/ormlette/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248721014,"owners_count":21151027,"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","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":["beam","database","db","elixir","erlang","frm","functional-programming","gleam","gleam-lang","gleamlang","object-relational-mapping","orm","pgo","postgre","postgres","postgresql","sql"],"created_at":"2024-10-14T22:06:01.346Z","updated_at":"2025-04-13T13:31:13.593Z","avatar_url":"https://github.com/ashercn97.png","language":"Gleam","readme":"# ormlette\n\nOrmlette is a delightful ORM (?) for Gleam. It's features include but are not limited to:\n\n- A (pretty awesome) schema DSL\n- A powerful query DSL that can be exported to `gleam-cake` Select statements, and used directly with `cake`\n- A CLI to automatically generate easy-use types, decoders, and more!\n- Changesets (like Ecto!)\n- Built-in validation library for changesets\n- Universal decoders (more on this later!)\n- Automatically generated record-to-dict functions\n\n\n\u003e Ormlette is currently in the very early stages of development, so advice/feature requests/bug reports are super helpful!\n\n\u003e [!NOTE]\n\u003e THESE DOCS ARE NOT COMPLETE YET! SOME MIGHT BE OUTDATED, IF SOMETHING DOESNT WORK JUST LEAVE AN ISSUE\n\u003e ALSO ALL THE FEATURES ARE NOT HERE YET. SO THIS MIGHT LAG BEHIND THE REAL STATE OF HTE PROJECT FOR A WHILE\n\n## Installation\nrun `gleam add ormlette` in your project.\n\n## Schema DSL\n\nThe schema DSL is the main way to define your database schema within ormlette. It allows you to define tables, columns, and relationships between tables.\n\nHere is what it looks like:\n\n```gleam\nimport ormlette/schema/create as c\n\npub fn users_table() {\n  c.define_table(\"users\", [\n    c.serial(\"id\") |\u003e c.primary,\n    c.text(\"name\") |\u003e c.nullable,\n  ])\n}\n```\n\nTo generate everything you need to work with databases, there are two commands to run:\nfirst run `gleam run -m ormlette -- meta` which generates some reflection values using Glerd, then run\n`gleam run -m ormlette -- orm` and look in the `src/eggs` directory to see everything that was generated!\n\n## Query DSL\n\nThe query DSL is the main way to build queries with ormlette. It allows you to select, insert, update, and delete data from your database. It is **heavily** based on `gleam-cake`, and uses it under the hood. Luckily, if you need to use features that `cake` supports and ormlette doesn't, you can just `q.export` the query, and use it directly with `cake`!\n\nHere is what the query DSL looks like:\n\n```gleam\nq.from_table(posts_table)\n    |\u003e q.inner_join(users_table)\n    |\u003e q.select([t.users().id, t.posts().id, \"posts.user_id\"]) //any one of these work, strings or usage types\n    |\u003e q.sql\n    |\u003e io.debug()\n    |\u003e run.run(db, users_posts_decoder.continuation) // this decoder is generated for us!\n    |\u003e io.debug\n```\n\nTo export the query, just run\n```gleam\n|\u003e q.export\n```\nAnd then you can, in the same pipeline, use it as a `cake/select` query! Awesome!\n\nHere is the magical part: the decoder puts the results into a type perfectly, every time. No matter what you select, how you select it, the order, etc., it is all put into the correct type, every time. All with one command!\n\n## CLI\n\nThe CLI is how you generate our \"universal decoders,\" decoder types, and usage types. So what are all of these?\n\n### Universal Decoders\n\nUniversal decoders are just dynamic decoders. The special part, though, is that they allow you to decode queries EVERY time. This means that even if you make two different `select` queries, each with a different order of selected columns, the **same** decoder will work with both queries!\n\nMoreover, it will also automatically generate join types and decoders with NO extra work from you. This means that if you have two tables that are related, there is no issue decoding these dynamic values! Pretty epic.\n\n### Decoder Types\n\nDecoder types are what the dynamic decoders decode the dynamic values into. This means that you will be able to reference columns of a row, without needing any extra work, and with them being the type you want!\n\n### Usage Types\n\nUsage types are not strictly necessary to enjoy using `ormlette`. But, (in my opinion) make everything much more pleasent. They gaurentee that you do not\na) miss-spell a column,\nb) reference a column that doesn't exist, and\nc) provide code completeion for the different columns!\n\nUsage types allow you to do something like:\n\n\n```gleam\nimport eggs/tables as t\n\nt.users().id // this gets the users table id column and turns it into something that can be used in a seelct column, for instance\n```\n\nThey are automatically generated, and in my opinion are worth using!\n\n### Record-to-dict\n\nThese functions allow you to convert records to dictionaries. Useful for changesets!\n\n\n## Changesets! (WIP)\n\nTaking after Ecto, ormlette supports Changesets. Changesets allow you to validate and trnsform data before you insert it into your database\n\n\u003e The changesets lib is currently working, but not with the nicest API, so I would not currently use them. THIS MESSAGE WILL BE UPDATED WHEN I DISAGREE WITH IT\n\n### Usage\nTo use a changeset, you can define custom error types to use, which allows it to feel more \"you\". For example:\n```gleam\npub type CustomError {\n  NameEmptyError(String)\n  InvalidEmailError(String)\n  AgeBelowMinimum(String)\n}\n```\n\nThen, you define validators. Validators work like this:\n\n```gleam\nimport ormlette/changesets/changesets\nimport ormlette_validate/string\nimport ormlette_validate/int\nimport ormlette_validate/option\n\npub fn validate_user(\n  u: decode.Users,\n) -\u003e changesets.Changeset(decode.Useers, CustomError) {\n  changesets.new(u)\n  |\u003e changesets.validate_field(\n    u.name,\n    optional.optional(\n      string.is_not_empty(InvalidEmailError(\"Email format is invalid.\")),\n    ),\n  )\n  |\u003e changesets.validate_field(\n    u.id,\n    optional.optional(int.min(1, InvalidEmailError(\"Email format is invalid.\"))),\n  )\n}\n```\n\nHopefully this is clear, I will update later with further instructions on the validation stuff.\n\nOkay, then finally you can run them by inserting a type. I will add examples for this later. IF SOMEONE WANTS TO HELP WITH DOCS THAT WOULD BE SUPER APPRECIATED\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashercn97%2Formlette","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fashercn97%2Formlette","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashercn97%2Formlette/lists"}