{"id":20477039,"url":"https://github.com/tableturn/dymo","last_synced_at":"2025-04-13T12:50:23.986Z","repository":{"id":62429016,"uuid":"146469428","full_name":"tableturn/dymo","owner":"tableturn","description":"For all your labelling and tagging needs!","archived":false,"fork":false,"pushed_at":"2020-10-16T18:26:43.000Z","size":199,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-27T03:51:17.877Z","etag":null,"topics":["database","dymo","hex","labelling","labels","polymorphism"],"latest_commit_sha":null,"homepage":"","language":"Elixir","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/tableturn.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}},"created_at":"2018-08-28T15:36:45.000Z","updated_at":"2020-10-16T18:26:46.000Z","dependencies_parsed_at":"2022-11-01T20:02:14.778Z","dependency_job_id":null,"html_url":"https://github.com/tableturn/dymo","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tableturn%2Fdymo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tableturn%2Fdymo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tableturn%2Fdymo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tableturn%2Fdymo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tableturn","download_url":"https://codeload.github.com/tableturn/dymo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248322608,"owners_count":21084336,"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":["database","dymo","hex","labelling","labels","polymorphism"],"created_at":"2024-11-15T15:25:13.458Z","updated_at":"2025-04-13T12:50:23.963Z","avatar_url":"https://github.com/tableturn.png","language":"Elixir","readme":"# Dymo\n\n[![Build Status](https://ci.linky.one/api/badges/tableturn/dymo/status.svg)](https://ci.linky.one/tableturn/dymo)\n[![Coverage Report](https://codecov.io/gh/tableturn/dymo/branch/master/graph/badge.svg)](https://codecov.io/gh/tableturn/dymo)\n[![Hex.pm](https://img.shields.io/hexpm/dt/dymo.svg)](https://hex.pm/packages/dymo)\n\n![Dymo Embosser](https://i.ebayimg.com/00/s/ODQ3WDc2Ng==/z/5mwAAOSw1x1UNkFc/$_35.JPG?set_id=2)\n\nFor all your labelling and tagging needs!™\n\n## Warning\n\nVersion `1.0.0` is **backward-incompatible** with other previous versions. Make sure to read the inline documentation to understand what this means, particularily the namespace fields that are required to be added on the `Tag` schema.\n\n## Motivations\n\nWhen it comes to polymorphism, it's always hard to find a match-all solution. Each known implementation have tradeoffs:\n\n1. Real polymorphism (`taggable_id`, `taggable_type` on the `Taggings` model) breaks database level foreign keys, and makes requests slower.\n2. Parent entity (Having each model have a `entity_id` refering to some `Entity` model) and having tags assigned to the `Entity` model via `entity_id` is cumbersome when performing complex queries and reverse queries.\n3. Multiple nullable foreign keys on the `Taggings` model (Eg `user_id`, `post_id`) is a very good solution but it could become hard to maintain and enforce if many models are taggable.\n4. One join table per taggable model (Eg `users_tags` and `posts_tags`) make it impossible to consolidate and search using SQL queries only.\n\nThis package offers an implementation that fits the 3rd and 4th approaches, and it offers shortcuts and mix tasks to make your life easier.\n\n## Installation\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed\nby adding `dymo` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:dymo, \"~\u003e 0.1.0\"}\n  ]\nend\n```\n\nYou should then configure Dymo to use the Repo you'd like. From your config, symply do:\n\n```elixir\nconfig :dymo,\n  ecto_repo: MyApp.Repo,\n  create_missing_tags_by_default: false\n```\n\n\u003e Note that the `create_missing_tags_by_default` option is set to `false` by default if you omit it, more on this later in this README.\n\nThen, you can install the `Tag` migration in your application (Note\nthat for umbrella apps, you'll need to first `cd` into the app\ncontaining your repo migrations):\n\n```text\n$ mix dymo.install\n* creating priv/repo/migrations\n* creating priv/repo/migrations/20180828154957_create_tags.exs\n```\n\nOnce done, you should start and make a join table for the model(s) you\nwant to be able to label. There is a mix task for this too!\n\n```text\n$ mix dymo.join_table MyApp.Post\n* creating priv/repo/migrations\n* creating priv/repo/migrations/20180828154958_create_posts_tags.exs\nOnce your database gets migrated, a new table posts_tags will be created.\n\nYou might want to add the following relationship to your MyApp.Post schema:\n  many_to_many :tags, Dymo.Tag,\n                join_through: \"posts_tags\",\n                on_replace: :delete,\n                unique: true\n\nAlternativelly, you can simply use the `taggable()` macro in your schema declaration,\nas long as you `use Dymo.Taggable` at the top of your module.\n```\n\n\u003e Note that you can tweak the migrations. For example, you can rename the `posts_tags` table to whatever you want (eg. `taggings`) as long as you consistently specify it when using the `Tagger` macros:\n\n```elixir\nuse Dymo.Taggable, join_table: \"taggings\"\n```\n\nOnce your database gets migrated, a new table posts_tags will be created.\n\nIf you follow the directives given by the tasks, you should then have\na fully labellable Post model. Congratulations!\n\n## Using Dymo.Taggable\n\nWhen a module uses `Dymo.Taggable`, many shortcut functions are\nbacked into it.\n\nIt becomes easy to achieve labelling-related tasks. All the examples\nbellow assyme that a `Post` module calls `use Dymo.Taggable`.\n\n\u003e If you would like to see more advanced uses and how Dymo's API works, a good starting point is probably [this file](test/dymo/end_to_end_test.exs), which calls on most functions that you'll ever need.\n\n### Editing Labels\n\nTo set the tags on an instance of a post:\n\n```elixir\npost\n  |\u003e Taggable.set_labels(~w(ten eleven), ns: :number, create_missing: true)\n  |\u003e Taggable.set_labels([{:car, \"Fort\"}, {:color, \"blue\"}], create_missing: true)\n  |\u003e Taggable.set_labels(\"Heineken\", ns: :beer, create_missing: true)\n```\n\nSimilarily, you can add / remove labels using `Post.add_labels` and `Post.remove_labels`.\n\nYou can also force labelling to only use existing tags (avoid on-the-fly creation) by\npassing appropriate options. For example:\n\n```elixir\npost\n  |\u003e Taggable.set_labels(~w(ten twelve), ns: :number, create_missing: false)\n  |\u003e Taggable.add_labels(\"Pierre\", ns: :name, create_missing: false)\n```\n\nThe default option for functions that either set or add labels is to **not** create non-\nexistent tags. Passing the `create_missing: true` option allows to create tags that were never seen\nby the system before. The reason behind this choice is to prevent Dymo from inadvertently creating\ninfinite labels in your database if you ever decided to leave an endpoint open allowing that.\n\nYou can override this behaviour by doing the following in your `config` files:\n\n```elixir\nconfig :dymo, create_missing_tags_by_default: true\n```\n\n## Unassignable Labels\n\nSometimes, tags might be present in a database but it should be forbidden for some of them to become\nassigned to a taggable. For example, if some of the tags are stored for the sole purpose of structure, if\nthey represent a parent tag that should never be attached itself, etc.\n\nDymo handles these cases by exposing an attribute on the `Tag` model named `assignable`. Tags can be attached\nto taggables as long as their `attachable`attribute is set to true - otherwise they will just be dropped from\ntagging operations.\n\nNote that operations such as `set_labels` or `add_labels` won't raise or error when unassignable tags are\ngiven. Instead, they will just ignore these tags completely.\n\n### Querying Labels\n\nTo get the labels associated with a given post, you have several options.\n\nUsing the association directly if you defined it:\n\n```elixir\npost\n  |\u003e Repo.preload(:tags)\n  |\u003e Map.get(:tags)\n  |\u003e Enum.map(\u0026(\u00261.label))\n```\n\nUsing the helper function:\n\n```elixir\n# If the namespace is unspecified, the `:root` namespace is used.\npost\n  |\u003e Taggable.labels()\n# Otherwise, only the labels from the given namespace are returned.\npost\n  |\u003e Taggable.labels(ns: :number)\n```\n\nYou can also query models that are tagged with specific labels by doing the following:\n\n```elixir\n# Match posts tagged with at least *one* of the tags.\nPost |\u003e Taggable.labelled_with(~w(ten eleven))\n# Match posts tagged with at least *all* the specified tags.\nPost |\u003e Taggable.labelled_with([{:color, \"blue\"}, {\"Heineken\", :beer}], match_all: true)\n```\n\n## Notes\n\nDocumentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)\nand published on [HexDocs](https://hexdocs.pm). Once published, the docs can\nbe found at [https://hexdocs.pm/dymo](https://hexdocs.pm/dymo).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftableturn%2Fdymo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftableturn%2Fdymo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftableturn%2Fdymo/lists"}