{"id":13879314,"url":"https://github.com/palkan/pgrel","last_synced_at":"2025-04-09T19:20:53.584Z","repository":{"id":28376163,"uuid":"31890215","full_name":"palkan/pgrel","owner":"palkan","description":"ActiveRecord extension for querying hstore and jsonb","archived":false,"fork":false,"pushed_at":"2020-12-18T11:29:47.000Z","size":99,"stargazers_count":92,"open_issues_count":2,"forks_count":7,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-02T13:01:57.426Z","etag":null,"topics":["activerecord","hacktoberfest","hstore","jsonb","postgresql"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/palkan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-09T09:46:24.000Z","updated_at":"2024-10-25T21:52:50.000Z","dependencies_parsed_at":"2022-08-24T18:13:58.393Z","dependency_job_id":null,"html_url":"https://github.com/palkan/pgrel","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/palkan%2Fpgrel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palkan%2Fpgrel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palkan%2Fpgrel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/palkan%2Fpgrel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/palkan","download_url":"https://codeload.github.com/palkan/pgrel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248095066,"owners_count":21046782,"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":["activerecord","hacktoberfest","hstore","jsonb","postgresql"],"created_at":"2024-08-06T08:02:17.029Z","updated_at":"2025-04-09T19:20:53.563Z","avatar_url":"https://github.com/palkan.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"[![Gem Version](https://badge.fury.io/rb/pgrel.svg)](https://rubygems.org/gems/pgrel)\n![Build](https://github.com/palkan/pgrel/workflows/Build/badge.svg)\n\n## Pgrel\n\nActiveRecord extension for querying hstore, array and jsonb.\n\nCompatible with **Rails** \u003e= 4.2 (including **Rails 6**).\n\n#### Install\n\nIn your Gemfile:\n\n```ruby\ngem \"pgrel\", \"~\u003e 0.3\"\n```\n\n### HStore\n\n#### Querying\n\nThe functionality is based on ActiveRecord `WhereChain`.\nTo start querying call `where(:store_name)` and chain it with store-specific call (see below).\n\nQuery by key value:\n\n```ruby\nHstore.where.store(:tags, a: 1, b: 2)\n#=\u003e select * from hstores where tags @\u003e '\"a\"=\u003e\"1\",\"b\"=\u003e\"2\"'\n\nHstore.where.store(:tags, a: [1, 2])\n#=\u003e select * from hstores where (tags @\u003e '\"a\"=\u003e\"1\"' or tags @\u003e '\"a\"=\u003e\"2\"')\n\nHstore.where.store(:tags, :a)\n#=\u003e select * from hstores where (tags @\u003e '\"a\"=\u003eNULL')\n\nHstore.where.store(:tags, { a: 1 }, { b: 2 })\n#=\u003e select * from hstores where (tags @\u003e '\"a\"=\u003e\"1\" or tags @\u003e \"b\"=\u003e\"2\"')\n```\n\nKeys existence:\n\n```ruby\n# Retrieve items that have key 'a' in 'tags'::hstore\nHstore.where.store(:tags).key(:a)\n#=\u003e select * from hstores where tags ? 'a'\n\n# Retrieve items that have both keys 'a' and 'b' in 'tags'::hstore\nHstore.where.store(:tags).keys('a', 'b')\n#=\u003e select * from hstores where tags ?\u0026 array['a', 'b']\n\n# Retrieve items that have either key 'a' or 'b' in 'tags'::hstore\nHstore.where.store(:tags).any('a', 'b')\n#=\u003e select * from hstores where tags ?| array['a', 'b']\n```\n\nValues existence:\n\n```ruby\n# Retrieve items that have value '1' OR '2'\nHstore.where.store(:tags).overlap_values(1, 2)\n#=\u003e select * from hstores where (avals(tags) \u0026\u0026 ARRAY['1', '2'])\n\n# Retrieve items that have values '1' AND '2'\nHstore.where.store(:tags).contains_values(1, 2)\n#=\u003e select * from hstores where (avals(tags) @\u003e ARRAY['1', '2'])\n```\n\nContainment:\n\n```ruby\nHstore.where.store(:tags).contains(a: 1, b: 2)\n#=\u003e select * from hstores where tags @\u003e '\\\"a\\\"=\u003e\\\"1\\\", \\\"b\\\"=\u003e\\\"2\\\"'\n\nHstore.where.store(:tags).contained(a: 1, b: 2)\n#=\u003e select * from hstores where tags \u003c@ '\\\"a\\\"=\u003e\\\"1\\\", \\\"b\\\"=\u003e\\\"2\\\"'\n```\n\n#### Update\n\nIs implemented through `ActiveRecord::Store::FlexibleHstore` and `ActiveRecord::Store::FlexibleJsonb`\nobjects. You can get them by sending `update_store(store_name)` to relation or class.\n\nAdd key, value pairs:\n\n```ruby\nHstore.update_store(:tags).merge(new_key: 1, one_more: 2)\nHstore.update_store(:tags).merge([[:new_key, 1], [:one_more, 2]])\n```\n\nDelete keys:\n\n```ruby\nHstore.update_store(:tags).delete_keys(:a, :b)\n```\n\nDelete key, value pairs:\n\n```ruby\nHstore.update_store(:tags).delete_pairs(a: 1, b: 2)\n```\n\n### JSONB\n\nAll queries and updates for Hstore also available for JSONB.\n\n**NOTE**. Querying by array value always resolves to `(... or ...)` statement.\nThus it's impossible to query json array value, e.g.:\n\n```ruby\nModel.create!(tags: {main: ['a', 'b']})\n\nModel.where.store(:tags, main: ['a', 'b']).empty? == true\n#=\u003e select * from models where  (tags @\u003e '{\\\"main\\\":\\\"a\\\"}' or tags @\u003e '{\\\"main\\\":\\\"b\\\"}')\n```\n\nPath query:\n\n```ruby\nModel.create!(tags: {main: ['a', 'b'], user: { name: 'john' } })\n\n# You can use object to query by simple value\nModel.where.store(:tags).path(user: { name: 'john' })\n#=\u003e select * from hstores where tags#\u003e\u003e'{\\\"user\\\",\\\"name\\\"}' = 'john'\n# or passing path parts as args one by one with value at the end\nModel.where.store(:tags).path(:user, :name, 'john')\n\n# Match by complex value (array or object)\nModel.where.store(:tags).path(:main, ['a', 'b'])\n#=\u003e select * from hstores where tags#\u003e'{\\\"main\\\"}' = '[\\\"a\\\",\\\"b\\\"]'\n```\n\n### Array\n\nArray stores support containment queries (just like Hstore and JSONB) and also `overlap` operator.\n\n**NOTE**. There are some other array operators ('ANY', 'ALL', querying by index - value) which I'm not going to implement – PRs are welcomed!\n\nOverlap:\n```ruby\nModel.where.store(:tags).overlap('a', 'b')\n#=\u003e select * from hstores where tags \u0026\u0026 '{\\\"a\\\",\\\"b\\\"}'\n```\n\n### Negation\n\nUse `not` before operator to constuct negation or pass arguments to `not` to run key-value query.\n\n```ruby\nModel.where.store(:tags).not.overlap('a', 'b')\n#=\u003e select * from hstores where not (tags \u0026\u0026 '{\\\"a\\\",\\\"b\\\"}')\n\nHstore.where.store(:tags).not(a: 1)\n#=\u003e select * from hstores where tags-\u003e'a' != '1'\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpalkan%2Fpgrel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpalkan%2Fpgrel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpalkan%2Fpgrel/lists"}