{"id":15713997,"url":"https://github.com/hashnuke/realm","last_synced_at":"2025-07-11T03:03:14.180Z","repository":{"id":66983744,"uuid":"14358536","full_name":"HashNuke/realm","owner":"HashNuke","description":"Database-independent model layer for Elixir with validations","archived":false,"fork":false,"pushed_at":"2013-12-29T03:47:05.000Z","size":168,"stargazers_count":11,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-12T23:30:47.146Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HashNuke.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-11-13T08:41:14.000Z","updated_at":"2023-07-18T22:38:23.000Z","dependencies_parsed_at":"2023-02-20T16:01:07.450Z","dependency_job_id":null,"html_url":"https://github.com/HashNuke/realm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/HashNuke/realm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HashNuke%2Frealm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HashNuke%2Frealm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HashNuke%2Frealm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HashNuke%2Frealm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HashNuke","download_url":"https://codeload.github.com/HashNuke/realm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HashNuke%2Frealm/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264719230,"owners_count":23653540,"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":[],"created_at":"2024-10-03T21:34:27.673Z","updated_at":"2025-07-11T03:03:14.157Z","avatar_url":"https://github.com/HashNuke.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Realm\n\nRealm is a simple model layer in Elixir with validation functions.\n\nIt is database-independent. Any interaction with databases are left to be implemented by the user (if required).\n\n\n## Usage\n\n* Define your record with a field called `__errors__` with a default value as an empty list\n* In your record, to add validations, define a `validate` function which takes a record as the first argument and also returns the record.\n\n\nOnce you have done those, you can use the `valid?` function on the record. It returns `true` or `false`.\n\n\n### Example\n\nAll validation functions return the record. The record is modified, with the errors added whenever necessary, so you will have to keep the modified record. To make things easier, use Elixir's pipes. Look at the example below:\n\n```elixir\ndefrecord Student, name: nil, phone: nil, country: nil, __errors__: [] do\n  use Realm\n  def validate(record) do\n    record\n    |\u003e validates_length(:name, [min: 1])\n    |\u003e validates_length(:country, [max: 2, message: \"use a valid 2-letter country code\"])\n    |\u003e validates_format(:phone, [format: %r/[0-9]+/], fn(record)-\u003e record.country == \"US\" end)\n  end\nend\n\njohn = Student[name: \"John Doe\"]\njohn.valid?           #=\u003e false\njohn.attributes       #=\u003e [name: \"John Doe\", phone: nil, country: nil]\njohn.validate.errors  #=\u003e [country: \"use a valid 2-letter country code\"]\n\n## We have a condition for the validating phone number\n## So let us update the country to US and validate again\njohn.country(\"US\").validate.errors  #=\u003e [phone: \"does not match format\"]\n```\n\nNote that the `validate` MUST return a record.\n\n## record.attributes()\n\nWhen you have a record of the type `User`, to get attributes do `record.attributes`.\n\nIt will return all fields and their values, except the field names that start and end with `__`. Like the `__errors__` field, which isn't returned.\n\n\n## Validation helpers\n\nIn your `validate` function, you can use the following helpers.\n\nIn all the helper functions, the first two arguments are\n\n* `record` - record to be validated\n* `field_name` - the field name in the record to validate\n\nEach validation helper can also be passed a function, that accepts a record, as a 4th argument. If such a function is passed, then the validation is performed only if the function returns true.\n\n\n#### validates_length(record, field_name, options)\n\nValidates length of Elixir strings (binaries) or lists (including single quoted strings).\n\nAccepts the following options:\n\n* `min` - minimum length of the field\n* `max` - maximum length of the field\n* `message` - the error message incase the validation fails\n\nEither `min` or `max` should be passed. Passing both is also fine.\nIf you do not pass a `message`, a standard error message will be used.\n\n```elixir\nvalidates_length(record, :name, [min: 3, max: 30])\n\nvalidates_length(record, :name, [min: 3, message: \"Name is not long enough\"])\n\nvalidates_length(record, :phone, [min: 10], fn(record)-\u003e record.country == \"US\" end)\n```\n\n#### validates_presence(record, field_name, options)\n\nValidates the value of the field is non-nil.\n\nThe only option is `message`, which is the custom error message.\n\n```elixir\nvalidates_presence(record, :age)\n\nvalidates_presence(record, :age, [message: \"Age must be entered\"])\n\n# In this case you can skip the options arg\nvalidates_presence(record, :age, fn(record)-\u003e record.country == \"US\" end)\n```\n\n#### validates_inclusion(record, field_name, options)\n\nValidates if the field contains only any of values from a specified list.\n\nValid options:\n\n* `in` - list of valid values. This is a __required__ option\n* `message` - custom error message\n\n```elixir\nvalidates_inclusion(record, :role, [in: [\"admin\", \"member\"]])\n\nvalidates_inclusion(record, :role, [in: [\"admin\", \"member\"], message: \"must have a valid role\"])\n\nvalidates_inclusion(record, :costume, fn(record)-\u003e record.role == \"superhero\" end)\n```\n\n#### validates_exclusion(record, field_name, options)\n\nValidates if the field doesn't contain any of values from a specified list.\n\nValid options:\n\n* `from` - list of invalid values. this is a __required__ option.\n* `message` - custom error message\n\n```elixir\nvalidates_exclusion(record, :role, [from: [\"superman\", \"batman\"]])\n\nvalidates_exclusion(record, :role, [from: [\"superman\", \"batman\"], message: \"You cannot be a superhero.\"])\n\nvalidates_exclusion(record, :role, [from: [\"ironman\", \"batman\"]], fn(record)-\u003e record.status != \"billionaire\" end)\n```\n\n#### validates_format(record, field_name, options)\n\nValidates if the format of the field's value matches the specified format.\n\nValid options:\n\n* `format` - regexp that specifies the format. This is a required option.\n* `message` - custom error message\n\n```elixir\nvalidates_format(record, :serial_number, [format: %r/[a-z][0-9]{3}/])\n\nvalidates_format(record, :serial_number, [format: %r/[a-z][0-9]{3}/], message: \"Invalid serial number\"])\n\nvalidates_format(record, :serial_number, [format: %r/[a-z][0-9]{3}/]], fn(record)-\u003e\n  record.expiry_year \u003c 2011\nend)\n```\n\n#### validates_uniqueness(record, field_name, options)\n\nValidates if the uniqueness of the record, by using the condition passed. Ideally you'll be using checking the database or some source to validate if this record is unique in some way.\n\nValid options:\n\n* `condition` - function to check the uniqueness. It should accept a record and should return `true` if the record's field's value is unique.\n* `message` - custom error message\n\nThis is the only function without a variant, which accepts a fourth argument (like other validation helpers). If you want any other condition, just specify it in the condition option itself.\n\n### Adding custom validation\n\nEasy peasy... add your custom validations to the `validate` function. Make sure you return the record at the end.\n\nWhen writing your own validation, to add your own errors for fields, use the following helpers\n\n#### add_error(record, field_name, error_message)\n\nAdd error to a record, for a field, after validation\n\nexample:\n\n```elixir\nadd_error(record, :username, \"already been taken\")\n```\n\n#### clear_errors(record)\n\nClear errors in a validated record\n\n```elixir\nclear_errors(record)\n```\n\n## Credits\n\nAuthor: [Akash Manohar](http://twitter.com/HashNuke)\n\nCopyright \u0026copy; 2013 under the MIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhashnuke%2Frealm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhashnuke%2Frealm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhashnuke%2Frealm/lists"}