{"id":13850045,"url":"https://github.com/MyMedsAndMe/marco_polo","last_synced_at":"2025-07-12T21:32:39.202Z","repository":{"id":32694663,"uuid":"36283972","full_name":"MyMedsAndMe/marco_polo","owner":"MyMedsAndMe","description":"Marco Polo is a binary OrientDB driver for Elixir.","archived":true,"fork":false,"pushed_at":"2023-01-19T12:23:20.000Z","size":392,"stargazers_count":69,"open_issues_count":4,"forks_count":9,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-10-18T01:53:24.601Z","etag":null,"topics":["dev"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MyMedsAndMe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-26T08:56:44.000Z","updated_at":"2024-03-28T00:22:38.000Z","dependencies_parsed_at":"2023-02-10T23:45:37.726Z","dependency_job_id":null,"html_url":"https://github.com/MyMedsAndMe/marco_polo","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyMedsAndMe%2Fmarco_polo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyMedsAndMe%2Fmarco_polo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyMedsAndMe%2Fmarco_polo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyMedsAndMe%2Fmarco_polo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MyMedsAndMe","download_url":"https://codeload.github.com/MyMedsAndMe/marco_polo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225658520,"owners_count":17503665,"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":["dev"],"created_at":"2024-08-04T20:00:57.331Z","updated_at":"2024-11-22T03:30:37.692Z","avatar_url":"https://github.com/MyMedsAndMe.png","language":"Elixir","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# marco_polo [DEPRECATED] \n\nMarco Polo is a binary OrientDB driver for Elixir.\n\nDocumentation is available at [http://hexdocs.pm/marco_polo][docs].\n\n## Usage\n\nAdd MarcoPolo as a dependency of your application inside your `mix.exs` file:\n\n```elixir\ndef deps do\n  [{:marco_polo, \"~\u003e 0.1\"}]\nend\n```\n\nNow run `mix deps.get` in your shell to fetch and compile MarcoPolo. To play with MarcoPolo, run `iex -S mix` in your project:\n\n```elixir\n{:ok, conn} = MarcoPolo.start_link(user: \"admin\",\n                                   password: \"admin\",\n                                   connection: {:db, \"GratefulDeadConcerts\"})\n\n{:ok, %{response: cluster_id}} = MarcoPolo.command(conn, \"CREATE CLASS ProgrammingLanguage\")\ncluster_id #=\u003e 15\n\nquery = \"INSERT INTO ProgrammingLanguage(name) VALUES (?)\"\n{:ok, %{response: doc}} = MarcoPolo.command(conn, query, params: [\"Elixir\"])\ndoc.rid     #=\u003e #MarcoPolo.RID\u003c#15:0\u003e\ndoc.version #=\u003e 1\ndoc.fields  #=\u003e %{\"name\" =\u003e \"Elixir\"}\n\nquery = \"SELECT FROM ProgrammingLanguage WHERE name = :name\"\n{:ok, %{response: [language]}} = MarcoPolo.command(conn, query, params: %{name: \"Elixir\"})\nlanguage == doc #=\u003e true\n```\n\n## Types\n\nSome OrientDB types are \"more specific\" than their Elixir counterparts. For\nexample, OrientDB can represent integers as ints (4 bytes), longs (8 bytes), or\nshorts (2 bytes). Elixir only knows about integers. For this reason, the OrientDB type can be forced (similarly to a type cast) from Elixir. For example, Elixir integers are encoded as ints (4 bytes) by default, but they can be forced to be encoded as shorts or longs by using a *tagged tuple*:\n\n```elixir\n332          #=\u003e gets encoded with 4 bytes as the int 332\n{:long, 332} #=\u003e gets encoded with 8 bytes as the long 332\n```\n\nThe same can be done for other types as well.\n\nThe following table shows how Elixir types map to OrientDB types and viceversa. The t\n\n\n| Elixir                                                                                 | Encoded as OrientDB type | Decoded in Elixir as                             |\n| :------                                                                                | :---------               | :-----------                                     |\n| `true`, `false`                                                                        | boolean                  | same as original                                 |\n| `83` or `{:int, 83}`                                                                   | integer                  | `83`                                             |\n| `{:short, 21}`                                                                         | short                    | `21`                                             |\n| `{:long, 944}`                                                                         | long                     | `944`                                            |\n| `{:float, 3.14}`                                                                       | float                    | `3.14`                                           |\n| `2.71` or `{:double, 2.71}`                                                            | double                   | `2.71`                                           |\n| `Decimal.new(3.14)` (using [Decimal][decimal])                                         | decimal                  | same as original                                 |\n| `\"foo\"`, `\u003c\u003c1, 2, 3\u003e\u003e`                                                                 | string                   | `\"foo\"`, `\u003c\u003c1, 2, 3\u003e\u003e`                           |\n| `{:binary, \u003c\u003c7, 2\u003e\u003e}`                                                                  | binary                   | `\u003c\u003c7, 2\u003e\u003e`                                       |\n| `%MarcoPolo.Date{year: 2015 month: 7, day: 1}`                                         | date                     | same as original                                 |\n| `%MarcoPolo.DateTime{year: 2015 month: 7, day: 1, hour: 0, min: 37, sec: 14, msec: 0}` | datetime                 | same as original                                 |\n| `%MarcoPolo.Document{}`                                                                | embedded                 | same as original                                 |\n| `[1, \"foo\", {:float, 3.14}]`                                                           | embedded list            | `[1, \"foo\", 3.14]`                               |\n| `#HashSet\u003c[2, 1]\u003e`                                                                     | embedded set             | `#HashSet\u003c[2, 1]\u003e`                               |\n| `%{\"foo\" =\u003e true}`                                                                     | embedded map             | `%{\"foo\" =\u003e true}`                               |\n| `%MarcoPolo.RID{cluster_id: 21, position: 3}`                                          | link                     | `%MarcoPolo.RID{cluster_id: 21, position: 3}`    |\n| `{:link_list, [%MarcoPolo.RID{}, ...]}`                                                | link list                | `{:link_list, [%MarcoPolo.RID{}, ...]}`          |\n| `{:link_set, #HashSet\u003c%MarcoPolo.RID{}, ...\u003e}`                                         | link set                 | `{:link_set, #HashSet\u003c%MarcoPolo.RID{}, ...\u003e}`   |\n| `{:link_map, %{\"foo\" =\u003e %MarcoPolo.RID{}, ...}}`                                       | link set                 | `{:link_map, %{\"foo\" =\u003e %MarcoPolo.RID{}, ...}}` |\n\n\nCaveats:\n\n* embedded maps and link maps only support strings as keys. During encoding,\n  MarcoPolo tries to convert all keys to strings using the `to_string/1`\n  function and the information about the original type is lost (so that at\n  decoding, all map keys are strings).\n* encoding and decoding of RidBags is described in the \"RidBags\" section below.\n\n### RidBags\n\nAs of version 0.1, MarcoPolo doesn't support tree RidBags. It only supports\nembedded RidBags.\n\nEmbedded RidBags are represented in Elixir like this:\n\n```elixir\n{:link_bag, [%MarcoPolo.RID, ...]}\n```\n\nTree-based RidBags will likely be supported in the upcoming versions. In the\nmeantime, if you need to, you can configure the OrientDB server so that it uses\nonly embedded RidBags (up to a number of links). To do this, set the value of\nthe `ridBag.embeddedToSbtreeBonsaiThreshold` option in the server's XML config\nto a very high value (e.g. 1 billion), so that embedded RidBags will be used up\nto that number of links. For example:\n\n\n```xml\n\u003cproperties\u003e\n  ...\n  \u003centry name=\"ridBag.embeddedToSbtreeBonsaiThreshold\" value=\"1000000000\" /\u003e\n\u003c/properties\u003e\n```\n\n## Fetch plans\n\nMarcoPolo supports OrientDB [fetch plans][odb-fetching-strategies]. Starting with these data:\n\n```elixir\n{:ok, conn} = MarcoPolo.start_link(user: \"root\",\n                                   password: \"root\",\n                                   connection: {:db, \"GratefulDeadConcerts\"})\n\n{:ok, %{response: country}} = MarcoPolo.command(conn, \"INSERT INTO Country(name) VALUES ('USA')\")\n\nquery = \"INSERT INTO City(name, country) VALUES ('New York', ?)\"\n{:ok, %{response: city}} = MarcoPolo.command(conn, query, params: [country.rid])\n\nquery = \"INSERT INTO Street(name, city) VALUES ('5th avenue', ?)\"\n{:ok, %{response: street}} = MarcoPolo.command(conn, query, params: [city.rid])\n```\n\nwe can fetch the city and the country when we fetch the street:\n\n```elixir\nquery = \"SELECT FROM Street WHERE name = '5th avenue'\"\n{:ok, %{response: [street], linked_records: linked}} = MarcoPolo.command(conn, query, fetch_plan: \"*:-1\")\n\nny = MarcoPolo.FetchPlan.resolve_links!(street.fields[\"city\"], linked)\nusa = MarcoPolo.FetchPlan.resolve_links!(ny.fields[\"country\"], linked)\n```\n\n## Working with graphs\n\nMarcoPolo supports working with graphs using the same `MarcoPolo.command/3`\nfunction showed above:\n\n```elixir\n{:ok, conn} = MarcoPolo.start_link(user: \"root\",\n                                   password: \"root\",\n                                   connection: {:db, \"GratefulDeadConcerts\"})\n\nquery = \"CREATE VERTEX V SET name = 'Pizza place'\"\n{:ok, %{response: pizza_place}} = MarcoPolo.command(conn, query)\nquery = \"CREATE VERTEX V SET name = 'Jane'\"\n{:ok, %{response: jane}} = MarcoPolo.command(conn, query)\n\nquery = \"CREATE EDGE HasEatenIn FROM ? to ?\"\nparams = [jane.rid, pizza_place.rid]\n{:ok, %{response: edge}} = MarcoPolo.command(conn, query, params: params)\n\nedge.fields[\"in\"]  #=\u003e {:link_list, [pizza_place.rid]}\nedge.fields[\"out\"] #=\u003e {:link_list, [jane.rid]}\n```\n\nThe `:graph` atom in the `MarcoPolo.start_link/1` function shuld reflect how the\ndatabase was created. If it was created as a graph database, then we use\n`:graph`, otherwise we use `:document`. The differences between graph and\ndocument databases are differences in the implementation on the server side; the\nAPI is exactly the same between the two types.\n\n## Scripting\n\nOrientDB supports server-side scripting (for example,\n[JavaScript][odb-javascript] and [SQL-batch][odb-sql-batch]). MarcoPolo supports\nthis feature through the `MarcoPolo.script/4` function:\n\n```elixir\n{:ok, conn} = MarcoPolo.start_link(user: \"root\",\n                                   password: \"root\",\n                                   connection: {:db, \"GratefulDeadConcerts\"})\n\n{:ok, _} = MarcoPolo.script(conn, \"Javascript\", \"\"\"\ndb.command('CREATE CLASS Number);\n\nfor (var i = 1; i \u003c= 10; i++) {\n  db.command('INSERT INTO Number(value) VALUES (' + i + ')');\n}\n\"\"\")\n```\n\n## Transactions\n\nOrientDB supports server-side transactions, meaning transactions that happen\nonly on the server. The clients sends all the operations it wants to perform in\nthe transactions, and the server either performs them all atomically or reverts\nall of them if there's an error in one of them. To perform a transaction in\nMarcoPolo:\n\n```elixir\n{:ok, conn} = MarcoPolo.start_link(user: \"root\",\n                                   password: \"root\",\n                                   connection: {:db, \"GratefulDeadConcerts\"})\n\n{:ok, resp} = MarcoPolo.transaction(conn, [\n  {:create, %MarcoPolo.Document{class: \"Foo\", fields: %{\"foo\" =\u003e \"bar\"}}},\n  {:delete, %MarcoPolo.Document{rid: %MarcoPolo.RID{cluster_id: 10, position: 39}}},\n])\n\nresp.created\n#=\u003e %MarcoPolo.Document{class: \"Foo\", fields: %{\"foo\" =\u003e \"bar\"}, rid: %MarcoPolo.RID{...}}\n\nresp.updated\n#=\u003e []\n```\n\nTo perform transactions with manual rollback (similar to the ones in most\nrelational databases), you have to use server-side scripting. For example, you\ncan perform a transaction by using a SQL script:\n\n```elixir\n{:ok, conn} = MarcoPolo.start_link(user: \"root\",\n                                   password: \"root\",\n                                   connection: {:db, \"GratefulDeadConcerts\"})\n\nscript = \"\"\"\nbegin\nlet account = create vertex Account set name = 'Luke'\nlet city = select from City where name = 'London' lock record\nlet edge = create edge Lives from $account to $city\ncommit\nreturn $edge\n\"\"\"\n\nMarcoPolo.script(conn, \"SQL\", script)\n```\n\n## Live query\n\n**Note**: this is an *experimental feature in OrientDB*, and thus subject to\nfrequent changes. It should be considered experimental in MarcoPolo as well.\n\n[Live Queries][odb-live-query] are OrientDB's take on PubSub. A client starts\n\"watching\" a given query, and OrientDB sends messages to that client every time\nsomething happens that changes the result of the query. For example, a `LIVE\nSELECT FROM Person` query subscribes to the `SELECT FROM Person` query. If a\nclient adds record to `Person`, then all clients subscribed to that query get a\nmessage that says a new `Person` has been created. Subscriptions are identified\nby tokens.\n\nAll of this is pretty straightforward in MarcoPolo:\n\n```elixir\n{:ok, conn} = MarcoPolo.start_link(user: \"root\",\n                                   password: \"root\",\n                                   connection: {:db, \"GratefulDeadConcerts\"})\n\n# Let's keep the token around so that we can unsubscribe later\n{:ok, token} = MarcoPolo.live_query(conn, \"LIVE SELECT FROM Person\", self())\n\n# The third argument to live_query/3 is the pid that will receive messages from\n# the live query\nMarcoPolo.command(conn, \"INSERT INTO Person(name) VALUES ('Olivia Dunham')\")\nreceive do msg -\u003e msg end\n#=\u003e {:orientdb_live_query, token, {:create, %MarcoPolo.Document{class: \"Person\", ...}}}\n\nMarcoPolo.command(conn, \"UPDATE Person SET name = 'Fauxlivia Dunham' WHERE name = 'Olivia Dunham'\")\nreceive do msg -\u003e msg end\n#=\u003e {:orientdb_live_query, token, {:update, %MarcoPolo.Document{class: \"Person\", ...}}}\n\n# Ok, enough with Fringe references\n:ok = MarcoPolo.live_query_unsubscribe(conn, token)\n```\n\n## Contributing\n\nFor more information on how to contribute to MarcoPolo (including how to clone\nthe repository and run tests), have a look at the\n[CONTRIBUTING](CONTRIBUTING.md) file.\n\n## License\n\nSee the [LICENSE](LICENSE) file.\n\n\n[docs]: http://hexdocs.pm/marco_polo\n[decimal]: https://github.com/ericmj/decimal\n[odb-javascript]: http://orientdb.com/docs/last/Javascript-Command.html\n[odb-sql-batch]: http://orientdb.com/docs/last/SQL-batch.html\n[odb-fetching-strategies]: http://orientdb.com/docs/last/Fetching-Strategies.html\n[odb-live-query]: https://orientdb.com/docs/last/Live-Query.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMyMedsAndMe%2Fmarco_polo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMyMedsAndMe%2Fmarco_polo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMyMedsAndMe%2Fmarco_polo/lists"}