{"id":25534831,"url":"https://github.com/diegojromerolopez/babik","last_synced_at":"2026-03-07T05:33:10.249Z","repository":{"id":59150918,"uuid":"135918462","full_name":"diegojromerolopez/babik","owner":"diegojromerolopez","description":"A Django queryset-like API for Ruby on Rails","archived":false,"fork":false,"pushed_at":"2022-07-17T17:35:52.000Z","size":286,"stargazers_count":3,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-30T00:45:10.906Z","etag":null,"topics":["activerecord","mysql","postgresql","query-builder","ruby","ruby-gem","ruby-on-rails","sql","sqlite3"],"latest_commit_sha":null,"homepage":null,"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/diegojromerolopez.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":"2018-06-03T15:55:07.000Z","updated_at":"2021-09-08T15:51:59.000Z","dependencies_parsed_at":"2022-09-14T04:01:25.140Z","dependency_job_id":null,"html_url":"https://github.com/diegojromerolopez/babik","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/diegojromerolopez/babik","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fbabik","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fbabik/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fbabik/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fbabik/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diegojromerolopez","download_url":"https://codeload.github.com/diegojromerolopez/babik/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegojromerolopez%2Fbabik/sbom","scorecard":{"id":341425,"data":{"date":"2025-08-11","repo":{"name":"github.com/diegojromerolopez/babik","commit":"9224a0ffcc19b41a17218f85f03f2ad6c7408670"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"100 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-h47h-mwp9-c6q6","Warn: Project is vulnerable to: GHSA-4g8v-vg43-wpgf","Warn: Project is vulnerable to: GHSA-7wjx-3g7j-8584","Warn: Project is vulnerable to: GHSA-8727-m6gj-mc37","Warn: Project is vulnerable to: GHSA-8xww-x3g3-6jcv","Warn: Project is vulnerable to: GHSA-hjg4-8q5f-x6fm","Warn: Project is vulnerable to: GHSA-jp5v-5gx4-jmj9","Warn: Project is vulnerable to: GHSA-mm33-5vfq-3mm3","Warn: Project is vulnerable to: GHSA-p84v-45xj-wwqj","Warn: Project is vulnerable to: GHSA-vfg9-r3fq-jvx4","Warn: Project is vulnerable to: GHSA-vfm5-rmrh-j26v","Warn: Project is vulnerable to: GHSA-wh98-p28r-vrc9","Warn: Project is vulnerable to: GHSA-x76w-6vjr-8xgj","Warn: Project is vulnerable to: GHSA-65cv-r6x7-79hv","Warn: Project is vulnerable to: GHSA-86g5-2wh3-gc9j","Warn: Project is vulnerable to: GHSA-cfjv-5498-mph5","Warn: Project is vulnerable to: GHSA-ch3h-j2vf-95pv","Warn: Project is vulnerable to: GHSA-m63j-wh5w-c252","Warn: Project is vulnerable to: GHSA-xp5h-f8jf-rc8q","Warn: Project is vulnerable to: GHSA-xq5j-gw7f-jgj8","Warn: Project is vulnerable to: GHSA-q2qw-rmrh-vv42","Warn: Project is vulnerable to: GHSA-3hhc-qp5v-9p2j","Warn: Project is vulnerable to: GHSA-579w-22j4-4749","Warn: Project is vulnerable to: GHSA-76r7-hhxj-r776","Warn: Project is vulnerable to: GHSA-8hc4-xxm3-5ppp","Warn: Project is vulnerable to: GHSA-7rr7-rcjw-56vj","Warn: Project is vulnerable to: GHSA-8h22-8cf7-hq6g","Warn: Project is vulnerable to: GHSA-m42x-37p3-fv5w","Warn: Project is vulnerable to: GHSA-w749-p3v6-hccq","Warn: Project is vulnerable to: GHSA-2p68-f74v-9wc6","Warn: Project is vulnerable to: GHSA-cr5q-6q9f-rq6q","Warn: Project is vulnerable to: GHSA-j6gc-792m-qgm2","Warn: Project is vulnerable to: GHSA-pj73-v5mw-pm9j","Warn: Project is vulnerable to: GHSA-23c2-gwp5-pxw9","Warn: Project is vulnerable to: GHSA-jphg-qwrw-7w9g","Warn: Project is vulnerable to: GHSA-228g-948r-83gx","Warn: Project is vulnerable to: GHSA-3x8r-x6xp-q4vm","Warn: Project is vulnerable to: GHSA-486f-hjj9-9vhh","Warn: Project is vulnerable to: GHSA-c3gv-9cxf-6f57","Warn: Project is vulnerable to: GHSA-g4xq-jx4w-4cjv","Warn: Project is vulnerable to: GHSA-242x-7cm6-4w8j","Warn: Project is vulnerable to: GHSA-286v-pcf5-25rc","Warn: Project is vulnerable to: GHSA-2qc6-mcvw-92cw","Warn: Project is vulnerable to: GHSA-2rr5-8q37-2w7h","Warn: Project is vulnerable to: GHSA-353f-x4gh-cqq8","Warn: Project is vulnerable to: GHSA-4hm9-844j-jmxp","Warn: Project is vulnerable to: GHSA-59gp-qqm7-cw4j","Warn: Project is vulnerable to: GHSA-5w6v-399v-w3cc","Warn: Project is vulnerable to: GHSA-6qvp-r6r3-9p7h","Warn: Project is vulnerable to: GHSA-7553-jr98-vx47","Warn: Project is vulnerable to: GHSA-7rrm-v45f-jp64","Warn: Project is vulnerable to: GHSA-cf46-6xxh-pc75","Warn: Project is vulnerable to: GHSA-cgx6-hpwq-fhv5","Warn: Project is vulnerable to: GHSA-cr5j-953j-xw5p","Warn: Project is vulnerable to: GHSA-crjr-9rc5-ghw8","Warn: Project is vulnerable to: GHSA-fq42-c5rg-92c2","Warn: Project is vulnerable to: GHSA-gx8x-g87m-h5q6","Warn: Project is vulnerable to: GHSA-jc36-42cf-vqwj","Warn: Project is vulnerable to: GHSA-jw9f-hh49-cvp9","Warn: Project is vulnerable to: GHSA-mrxw-mxhj-p664","Warn: Project is vulnerable to: GHSA-pxvg-2qj5-37jq","Warn: Project is vulnerable to: GHSA-qxcg-xjjg-66mj","Warn: Project is vulnerable to: GHSA-r95h-9x8f-r3f7","Warn: Project is vulnerable to: GHSA-v4f8-2847-rwm7","Warn: Project is vulnerable to: GHSA-v6gp-9mmm-c6p5","Warn: Project is vulnerable to: GHSA-vmfx-gcfq-wvm2","Warn: Project is vulnerable to: GHSA-vr8q-g5c7-m54m","Warn: Project is vulnerable to: GHSA-vvfq-8hwr-qm4m","Warn: Project is vulnerable to: GHSA-xc9x-jj77-9p9j","Warn: Project is vulnerable to: GHSA-xh29-r2w5-wx8m","Warn: Project is vulnerable to: GHSA-xxx9-3xcr-gjj3","Warn: Project is vulnerable to: GHSA-22f2-v57c-j9cx","Warn: Project is vulnerable to: GHSA-3h57-hmj3-gj3p","Warn: Project is vulnerable to: GHSA-54rr-7fvw-6x8f","Warn: Project is vulnerable to: GHSA-5f9h-9pjv-v6j7","Warn: Project is vulnerable to: GHSA-5r2p-j47h-mhpg","Warn: Project is vulnerable to: GHSA-65f5-mfpf-vfhj","Warn: Project is vulnerable to: GHSA-7g2v-jj9q-g3rg","Warn: Project is vulnerable to: GHSA-7wqh-767x-r66v","Warn: Project is vulnerable to: GHSA-8cgq-6mh2-7j6v","Warn: Project is vulnerable to: GHSA-93pm-5p5f-3ghx","Warn: Project is vulnerable to: GHSA-c6qg-cjj8-47qp","Warn: Project is vulnerable to: GHSA-gjh7-p2fx-99vx","Warn: Project is vulnerable to: GHSA-hg78-4f6x-99wq","Warn: Project is vulnerable to: GHSA-hrqr-hxpp-chr3","Warn: Project is vulnerable to: GHSA-hxqx-xwvh-44m2","Warn: Project is vulnerable to: GHSA-j6w9-fv6q-3q52","Warn: Project is vulnerable to: GHSA-rqv2-275x-2jq5","Warn: Project is vulnerable to: GHSA-vpfw-47h7-xj4g","Warn: Project is vulnerable to: GHSA-wq4h-7r42-5hrr","Warn: Project is vulnerable to: GHSA-xj5v-6v4g-jfw6","Warn: Project is vulnerable to: GHSA-5x79-w82f-gw8w","Warn: Project is vulnerable to: GHSA-9h9g-93gc-623h","Warn: Project is vulnerable to: GHSA-mcvf-2q2m-x72m","Warn: Project is vulnerable to: GHSA-pg8v-g4xq-hww9","Warn: Project is vulnerable to: GHSA-rrfc-7g8p-99q8","Warn: Project is vulnerable to: GHSA-m42h-mh85-4qgc","Warn: Project is vulnerable to: GHSA-jppv-gw3r-w3q8","Warn: Project is vulnerable to: GHSA-5cm2-9h8c-rvfx","Warn: Project is vulnerable to: GHSA-g6wq-qcwm-j5g2"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T05:59:05.361Z","repository_id":59150918,"created_at":"2025-08-18T05:59:05.361Z","updated_at":"2025-08-18T05:59:05.361Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30189540,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T17:33:53.563Z","status":"ssl_error","status_checked_at":"2026-03-06T17:33:51.678Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","mysql","postgresql","query-builder","ruby","ruby-gem","ruby-on-rails","sql","sqlite3"],"created_at":"2025-02-20T03:29:04.544Z","updated_at":"2026-03-07T05:33:10.223Z","avatar_url":"https://github.com/diegojromerolopez.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Babik\n\n[![Build Status](https://travis-ci.com/diegojromerolopez/babik.svg?branch=master)](https://travis-ci.com/diegojromerolopez/babik)\n[![Maintainability](https://api.codeclimate.com/v1/badges/8a64e9a43c77d31a0df1/maintainability)](https://codeclimate.com/github/diegojromerolopez/babik/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/8a64e9a43c77d31a0df1/test_coverage)](https://codeclimate.com/github/diegojromerolopez/babik/test_coverage)\n\n![Gem](https://img.shields.io/gem/v/babik.svg)\n\nA Django [queryset-like](https://docs.djangoproject.com/en/2.0/ref/models/querysets/) API for [Ruby on Rails](https://rubyonrails.org/).\n\nSee [Roadmap](#roadmap) to check future enhancements.\n\nSee the [QuerySet API](/doc/api/queryset.md) if you know this library and want to\nsee the documentation.\n\nContact [me](mailto:diegojromerolopez@gmail.com) if you are interested in\nhelping me developing it or **make a PR with some feature or fix**.\n\n## What's this?\n\nThis is a library to help you to make queries based on associations without having\nto worry about doing joins or writing the exact name of the related table as a prefix\nof the foreign field conditions.\n\n### Example: Blog platform in Rails\n\nSuppose you are developing a blog platform with the following [schema](/test/config/db/schema.rb).\nCompare these two queries and check what is more easier to write:\n\nReturning all users with last name equals to 'Fabia' that are from Rome:\n```ruby\nUser.joins(:zones).where('last_name': 'Fabia').where('geo_zones.name': 'Rome')\n# vs.\nUser.objects.filter(last_name: 'Fabia', 'zone::name': 'Rome')\n```\n\nReturning all users with posts tagged with 'gallic' that are from Rome:\n```ruby\nUser.joins(:zones).joins(posts: :tags)\n    .where('last_name': 'Fabia')\n    .where('geo_zones.name': 'Rome')\n    .where('tags.name': 'gallic')\n# vs.\nUser.objects.filter(\n  last_name: 'Fabia',\n  'zone::name': 'Rome',\n  'posts::tags::name': 'gallic'\n)\n```\n\nThe second alternative is done by using the powerful [Babik querysets](/doc/api/queryset.md).\n\n[See Usage for more examples](#usage).\n\n## Install\n\nAdd to Gemfile:\n\n```\ngem install babik\n```\n\nor\n\n```\ngem install babik, git: 'git://github.com/diegojromerolopez/babik.git'\n```\n\n\n## Requirements\n\nRuby Version \u003e= 2.5\n\nInclude all [inverse relationships](http://guides.rubyonrails.org/association_basics.html#bi-directional-associations)\nin your models. **It is required to compute the object selection from instance**.\n\nAll your many-to-many relationships must have a through attribute.\nPer Rubocop guidelines, [using has_and_belongs_to_many is discouraged](https://github.com/rubocop-hq/rails-style-guide#has-many-through).\n\n## Configuration\n\nNo configuration is needed, Babik automatically includes two methods for your models:\n- **objects** class method to make queries for a model.\n- **objects** instance method to make queries from an instance. \n\n## Database support\n\n**PostgreSQL, MySQL and Sqlite are fully supported**.\n\n**MariaDB should work** as well (happy to solve any reported issues).\n\n**Babik MSSQL support development is stalled** by [activerecord-sqlserver-adapter Rails 5.2 support issue](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/636).\nAs soon as that issue is resolved, I will start working in providing full support to Babik to MSSQL.\n\nNo plan to offer Oracle support. Accepting contributors to port this library to Oracle.\n\nContributors can make PRs to support other RDBMS. \n\n## Documentation\n\nSee the [QuerySet API documentation](/doc/api/queryset.md).\n\n## Main differences with Django QuerySet system\n- Django does not make any distinct against relationships, local fields or lookups when selecting by\ncalling **filter**, **exclude** or **get**. Babik uses **::** for foreign fields.\n- Django has a [Q objects](https://docs.djangoproject.com/en/2.0/topics/db/queries/#complex-lookups-with-q-objects)\nthat allows the construction of complex queries. Babik allows passing an array to selection methods so\nthere is no need of this artifact.\n- Django [select_related](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#select-related)\nmethod cache the objects in the returned object.\nWe return a pair of objects and a hash with the associated objects. [See doc here](/doc/api/queryset/methods/dont_return_queryset.md#select-related).\n\n## Known issues\n\n### Clone in each non-modifying method call\n\nThis library uses [ruby_deep_clone](https://github.com/gmodarelli/ruby-deepclone/) to create a new QuerySet each time\na non-modifying method is called:\n\n```ruby\njulius = User.objects.filter(first_name: 'Julius')\njulius_caesar = julius.filter(last_name: 'Caesar')\n\nputs julius_caesar == julius\n# Will print false\n```\n\nThis library is somewhat unstable or not as stable as I would like.\n\n## Usage\n\nFor a complete reference and full examples of methods, see [documentation](/doc/README.md).\n\nSee [schema](/test/config/db/schema.rb) for information about this example's schema.\n\n### objects method\n\nA new **objects** method will be injected in your ActiveRecord classes and instances.\n\n#### Classes\n\nWhen called from a class, it will return a QuerySet of objects of this class.\n\n```ruby\nUser.objects.filter(last_name: 'Fabia')\n# Returning all users with last name equals to 'Fabia'\n\nUser.objects.filter(last_name: 'Fabia', 'zone::name': 'Rome')\n# Returning all users with last name equals to 'Fabia' that are from Rome\n```\n\n#### Instances\n\nWhen called from an instance, it will return the foreign related instances:\n\n```ruby\njulius = User.objects.get(first_name: 'Julius')\njulius.objects('posts').filter(stars__gte: 3)\n# Will return the posts written by Julius with 3 or more stars\n\njulius.objects('posts::tags').filter(name__in: ['war', 'battle', 'victory'])\n# Will return the tags of posts written by Julius with the names 'war', 'battle' and 'victory'\n```\n \n\n### Examples\n\n#### Selection\n\n[See the main docs](/doc/api/queryset/methods/return_queryset.md#filter).\n\nBasic selection is made by passing a hash to filter function:\n\n```ruby\nUser.objects.filter(first_name: 'Flavius', last_name: 'Josephus')\n# SELECT users.* FROM users WHERE first_name = 'Flavius' AND last_name = 'Josephus'\n```\n\nTo make an OR condition, pass an array of hashes:\n\n```ruby\nUser.objects.filter([{first_name: 'Flavius', last_name: 'Josephus'}, {last_name: 'Iosephus'}])\n# SELECT users.*\n# FROM users\n# WHERE (first_name = 'Flavius' AND last_name = 'Josephus') OR last_name = 'Iosephus'\n```\n\n#### Selection by exclusion\n\nYou can make negative conditions easily by using **exclude** function:\n\n```ruby\nUser.objects.exclude(first_name: 'Flavius', last_name: 'Josephus')\n# SELECT users.* FROM users WHERE NOT(first_name = 'Flavius' AND last_name = 'Josephus')\n```\n\nYou can combine **filter** and **exclude** to create complex queries:\n\n```ruby\nUser.objects.filter([{first_name: 'Marcus'}, {first_name: 'Julius'}]).exclude(last_name: 'Servilia')\n# SELECT users.*\n# FROM users\n# WHERE (first_name = 'Marcus' OR first_name = 'Julius') AND NOT(last_name = 'Servilia')\n```\n\n#### Selecting one object\n\n```ruby\n# Returns an exception if more than one object matches the selection\nUser.objects.get(id: 258) \n\n# Returns the first object that matches the selection\nUser.objects.filter(id: 258).first\n```\n\n#### Selecting from an ActiveRecord\n\nYou can filter from an actual ActiveRecord object:\n\n```ruby\nuser = User.objects.get(id: 258)\nuser.objects('posts::tags').filter(name__in: %w[battle history]).order_by(name: :ASC)\n# SELECT users.*\n# FROM users\n# LEFT JOIN posts posts_0 ON users.id = posts_0.author_id\n# LEFT JOIN post_tag post_tags_0 ON posts_0.id = post_tags_0.post_id \n# WHERE post_tags_0.name IN ['battle', 'history']\n# ORDER BY post_tags_0.name ASC\n```\n\n```ruby\njulius = User.objects.get(first_name: 'Julius', last_name: 'Caesar')\n\n# Will return a QuerySet with only the Julius Caesar user (useful for aggregations) \njulius.objects\n\n# Will return a QuerySet with all tags of posts of Julius Caesar\njulius.objects('posts::tags') \n\n# Will return a QuerySet with the GeoZone of Julius Caesar\njulius.objects('zone')\n\n```\n\n\n##### Lookups\n\n[See the main docs](/doc/api/queryset/methods/return_queryset.md#field-lookups).\n\nThere are other operators than equal to, these are implemented by using lookups:\n\n###### equal\n\n```ruby\nUser.objects.filter(first_name: 'Julius')\nUser.objects.filter(first_name__equal: 'Julius')\n# SELECT users.*\n# FROM users\n# WHERE first_name = 'Julius' \n```\n\n###### exact/iexact\n\n```ruby\nUser.objects.filter(last_name__exact: nil)\n# SELECT users.*\n# FROM users\n# WHERE last_name IS NULL \n```\n\n```ruby\nUser.objects.filter(last_name__exact: 'Postumia')\n# SELECT users.*\n# FROM users\n# WHERE last_name LIKE 'Postumia' \n```\n\ni preceding a comparison operator means case-insensitive version:\n\n```ruby\nUser.objects.filter(last_name__iexact: 'Postumia')\n# SELECT users.*\n# FROM users\n# WHERE last_name ILIKE 'Postumia' \n```\n\n###### contains/icontains\n\n```ruby\nUser.objects.filter(first_name__contains: 'iu')\n# SELECT users.*\n# FROM users\n# WHERE last_name LIKE '%iu%' \n```\n\n```ruby\nUser.objects.filter(first_name__icontains: 'iu')\n# SELECT users.*\n# FROM users\n# WHERE last_name ILIKE '%iu%' \n```\n\n###### endswith/iendswith\n\n```ruby\nUser.objects.filter(first_name__endswith: 'us')\n# SELECT users.*\n# FROM users\n# WHERE last_name LIKE '%us' \n```\n\n```ruby\nUser.objects.filter(first_name__iendswith: 'us')\n# SELECT users.*\n# FROM users\n# WHERE last_name ILIKE '%us' \n```\n\n###### startswith/istartswith\n\n```ruby\nUser.objects.filter(first_name__startswith: 'Mark')\n# SELECT users.*\n# FROM users\n# WHERE first_name LIKE 'Mark%' \n```\n\n```ruby\nUser.objects.filter(first_name__istartswith: 'Mark')\n# SELECT users.*\n# FROM users\n# WHERE first_name ILIKE 'Mark%' \n```\n\n###### in\n\n```ruby\nUser.objects.filter(first_name__in: ['Marcus', 'Julius', 'Crasus'])\n# SELECT users.*\n# FROM users\n# WHERE first_name IN ('Marcus', 'Julius', 'Crasus')\n```\n\nThere is also the possibility to use a subquery instead of a list of elements:\n\n```ruby\nPost.objects.filter(id__in: @seneca_sr.objects(:posts).project(:id))\n# SELECT posts.*\n# FROM posts\n# WHERE id IN (SELECT posts.id FROM posts WHERE author_id = 2)\n```\n\n\n###### Comparison operators: gt, gte, lt, lte\n\n```ruby\nPosts.objects.filter(score__gt: 4)\n# SELECT posts.*\n# FROM posts\n# WHERE score \u003e 4\n```\n\n```ruby\nPosts.objects.filter(score__lt: 4)\n# SELECT posts.*\n# FROM posts\n# WHERE score \u003c 4\n```\n\n```ruby\nPosts.objects.filter(score__gte: 4)\n# SELECT posts.*\n# FROM posts\n# WHERE score \u003e= 4\n```\n\n```ruby\nPosts.objects.filter(score__lte: 4)\n# SELECT posts.*\n# FROM posts\n# WHERE score \u003c= 4\n```\n\n\n###### Other lookups\n\nSee more [here](/doc/api/queryset/lookups.md).\n\n#### Selection by foreign model field\n\nThe main feature of Babik is filtering by foreign keys. \n\nRemember:\n\n- **Your associations must have always an inverse (by making use of inverse_of)**. \n\n- **Many-to-many** relationships are only supported when based on **has_many through**.\n[Reason](https://github.com/rubocop-hq/rails-style-guide#has-many-through). \n\n##### Belongs to relationships\n\n```ruby\nUser.objects.filter('zone::name': 'Roman Empire')\n# SELECT users.*\n# FOR users\n# LEFT JOIN geo_zones users_zone_0 ON users.zone_id = parent_zones_0.id\n# WHERE  users_zone_0 = 'Roman Empire'\n```\n\nAll depth levels are accepted:\n\n```ruby\nUser.objects.filter('zone::parent_zone::parent_zone::name': 'Roman Empire')\n# SELECT users.*\n# FOR users\n# LEFT JOIN geo_zones users_zone_0 ON users.zone_id = parent_zones_0.id\n# LEFT JOIN geo_zones parent_zones_0 ON users_zone_0.parent_id = parent_zones_0.id\n# LEFT JOIN geo_zones parent_zones_1 ON parent_zones_0.parent_id = parent_zones_1.id\n# WHERE  parent_zones_1 = 'Roman Empire'\n```\n\n##### Has many relationships\n\n```ruby\nUser.objects.distinct.filter('posts::tag::name': 'history')\n# SELECT DISTINCT users.*\n# FOR users\n# LEFT JOIN posts posts_0 ON users.id = posts_0.author_id\n# LEFT JOIN post_tag post_tags_0 ON posts_0.id = post_tags_0.post_id\n# LEFT JOIN tags tags_0 ON post_tags_0.tag_id = tags_0.id\n# WHERE  post_tag_tags_0 = 'history'\n```\n\nNote by using [distinct](/doc/api/queryset/methods/return_queryset.md#distinct)\nwe have avoided duplicated users (in case the same user has more than one post\nwith tagged as 'history').\n\n#### Projections\n\n[See the main docs](/doc/api/queryset/methods/dont_return_queryset.md#project).\n\nReturn\nan [ActiveRecord Result](http://api.rubyonrails.org/classes/ActiveRecord/Result.html)\nwith only the fields you are interested\nby using a [projection](/doc/api/queryset/methods/dont_return_queryset.md#project):\n\n```ruby\np User.objects.filter('zone::name': 'Castilla').order_by('first_name').project('first_name', 'email')\n\n# Query:\n# SELECT users.first_name, users.email\n# FROM users\n# LEFT JOIN geo_zones users_zone_0 ON users.zone_id = parent_zones_0.id\n# WHERE users_zone_0.name = 'Castilla'\n# ORDER BY users.first_name ASC \n\n# Result:\n# [\n#   { first_name: 'Isabel I', email: 'isabeli@example.com' },\n#   { first_name: 'Juan II', email: 'juanii@example.com' },\n#   { first_name: 'Juana I', email: 'juanai@example.com' }\n# ]\n```\n\n#### Select related\n\n[See the main docs](/doc/api/queryset/methods/dont_return_queryset.md#select-related).\n\n**select_related** method allows fetching an object and its related ones at once.\n\n```ruby\nUser.filter(first_name: 'Julius').select_related(:zone)\n# Will return in each iteration a list with two elements, the first one\n# will be the User instance, and the other one a hash where the keys are\n# each one of the association names and the value the associated object \n```\n\n##### Order\n\n[See the main docs](/doc/api/queryset/methods/return_queryset.md#order-by).\n\nOrdering by one field (ASC)\n\n```ruby\nUser.objects.order_by(:last_name)\n# SELECT users.*\n# FOR users\n# ORDER BY users.last_name ASC \n```\n\nOrdering by one field (DESC)\n\n```ruby\nUser.objects.order_by(%i[last_name, DESC])\n# SELECT users.*\n# FOR users\n# ORDER BY users.last_name DESC \n```\n\nOrdering by several fields\n\n```ruby\nUser.objects.order_by(%i[last_name, ASC], %i[first_name, ASC])\n# SELECT users.*\n# FOR users\n# ORDER BY users.last_name ASC, users.first_name ASC\n```\n\nOrdering by foreign fields\n\n```ruby\nUser.objects\n    .filter('zone::name': 'Roman Empire')\n    .order_by(%i[zone::name, ASC], %i[created_at, DESC])\n# SELECT users.*\n# FOR users\n# LEFT JOIN geo_zones users_zone_0 ON users.zone_id = parent_zones_0.id\n# WHERE  users_zone_0 = 'Roman Empire'\n# ORDER BY parent_zones_0.name ASC, users.created_at DESC \n```\n\nInverting the order\n\n```ruby\n\nUser.objects\n    .filter('zone::name': 'Roman Empire')\n    .order_by(%i[zone::name, ASC], %i[created_at, DESC]).reverse\n# SELECT users.*\n# FOR users\n# LEFT JOIN geo_zones users_zone_0 ON users.zone_id = parent_zones_0.id\n# WHERE  users_zone_0 = 'Roman Empire'\n# ORDER BY parent_zones_0.name DES, users.created_at ASC \n```\n\n#### Delete\n\n[See the main docs](/doc/api/queryset/methods/dont_return_queryset.md#delete).\n\nThere is no standard DELETE from foreign field SQL statement, so for now\nthe default implementation makes use of DELETE WHERE id IN SELECT subqueries.\n\nFuture implementations will use joins.\n\n##### Delete by local field\n\n```ruby\nUser.objects.filter('first_name': 'Julius', 'last_name': 'Caesar').delete\n# DELETE\n# FROM users\n# WHERE id IN ( \n#   SELECT users.*\n#   FOR users\n#   WHERE users.first_name = 'Julius' AND users.last_name = 'Caesar'\n# ) \n```\n\n##### Delete by foreign field\n\n```ruby\nGeoZone.get('name': 'Roman Empire').objects('users').delete\nUser.objects.filter('zone::name': 'Roman Empire').delete\n# Both statements are equal:\n# DELETE\n# FROM users\n# WHERE id IN ( \n#   SELECT users.*\n#   FOR users\n#   LEFT JOIN geo_zones users_zone_0 ON users.zone_id = parent_zones_0.id\n#   WHERE  users_zone_0 = 'Roman Empire'\n# ) \n```\n\n## Update\n\n[See the main docs](/doc/api/queryset/methods/dont_return_queryset.md#update).\n\nSimilar to what happens in when running SQL-delete statements, there is no\nstandard UPDATE from foreign field SQL statement, so for now\nthe default implementation makes use of UPDATE SET ... WHERE id IN SELECT subqueries.\n\nFuture implementations will use joins.\n\n##### Update by local field\n\n```ruby\nUser.objects.filter('first_name': 'Julius', 'last_name': 'Caesar').update(first_name: 'Iulius')\n# UPDATE SET first_name = 'Iulius'\n# FROM users\n# WHERE id IN ( \n#   SELECT users.*\n#   FOR users\n#   WHERE users.first_name = 'Julius' AND users.last_name = 'Caesar'\n# ) \n```\n\n##### Update by foreign field\n\n```ruby\nGeoZone.get(name: 'Roman Empire').objects('users').filter(last_name__isnull: true).update(last_name: 'Romanum')\nUser.objects.filter('zone::name': 'Roman Empire', last_name__isnull: true).update(last_name: 'Romanum')\n# Both statements are equal:\n# UPDATE SET last_name = 'Romanum'\n# FROM users\n# WHERE id IN ( \n#   SELECT users.*\n#   FOR users\n#   LEFT JOIN geo_zones users_zone_0 ON users.zone_id = parent_zones_0.id\n#   WHERE  users_zone_0 = 'Roman Empire' AND users.last_name IS NULL\n# ) \n```\n\n##### Update field by using an actual value of the record\n\n```ruby\nPost.objects.filter(stars__gte: 1, stars__lte: 4)\n    .update(stars: Babik::QuerySet::Update::Increment.new('stars'))\n# UPDATE SET stars = stars + 1\n# FROM posts\n# WHERE id IN ( \n#   SELECT posts.*\n#   FOR posts\n#   WHERE  posts.stars \u003e= 1 AND posts.stars \u003c= 4\n# ) \n```\n\n## Documentation\n\nSee the [documentation](doc/README.md) for more information\nabout the [API](doc/README.md#queryset-api) and the\ninternals of this library.\n\n\n\n## Unimplemented API\n\n### Methods that return a QuerySet\n\n#### Will be implemented\n\n- [prefetch_related](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#prefetch_related)\n\n#### Will not be implemented\n\n- [dates](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#dates): [project](/doc/api/queryset/methods/dont_return_queryset.md#project) allow transformer functions that can be used to get dates in the desired format.\n- [datetimes](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#datetimes): [project](/doc/api/queryset/methods/dont_return_queryset.md#project) allow transformer functions that can be used to get datetimes in the desired format.\n- [extra](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#extra): better use the ActiveRecord API or for raw SQL use [find_by_sql](https://apidock.com/rails/ActiveRecord/Querying/find_by_sql).\n- [values](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#values): can be computed using [project](/doc/api/queryset/methods/dont_return_queryset.md#project).\n- [values_list](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#values_list):  can be computed using [project](/doc/api/queryset/methods/dont_return_queryset.md#project).\n- [raw](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#raw): use ActiveRecord [find_by_sql](https://apidock.com/rails/ActiveRecord/Querying/find_by_sql). Babik is not\nfor doing raw queries, is for having an additional query system to the ActiveRecord one.\n- [using](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#using): to change the database a model\nis better to use something like [this](https://stackoverflow.com/questions/180349/how-can-i-dynamically-change-the-active-record-database-for-all-models-in-ruby-o).\n\n#### Under consideration\n\nI am not sure it is a good idea to allow deferred loading or fields. I think is a poor solution for tables with too many\nfields. Should I have to take the trouble to implement this two methods?:\n\n- [defer](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#defer)\n- [only](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#only)\n\n\n\n### Methods that don't return a QuerySet\n\n#### Will not be implemented\n\nThe aim of this library is to help make complex queries, not re-implementing the\nwell-defined and working API of Rails. All of this methods have equivalents in Rails,\nbut if you are interested, I'm accepting pull-requests. \n\n- [create](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#create)\n- [get_or_create](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#get_or_create)\n- [update_or_create](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#update_or_create)\n- [bulk_create](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#bulk_create)\n- [in_bulk](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#in_bulk)\n- [iterator](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#iterator)\n- [as_manager](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#as_manager)\n\n\n### Aggregation functions\n\n#### Will be not implemented\n\n- [expression](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#expression):\nthere are no [Query Expressions](https://docs.djangoproject.com/en/2.0/ref/models/expressions/)\nin Babik, will be possible with the custom aggregations.\n- [output_field](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#output_field): already possible passing a hash where the key is the output field. \n- [filter](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#id6): there are no Q objects in Babik.\n- [**extra](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#id7): no way to include\nextra keyword arguments in the aggregates for now. \n\n\n## Roadmap\n\n### Increase code quality\n\nThis project must follow Rubocop directives and pass Reek checks.\n\n### Make a babik-test project\n\nMake a repository with the test schema to check the library is really working.\n\n### Deploy in rubygems\n\nDeploy gem in rubygems.\n\n### Prefect\n\n[Object prefetching](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#prefetch-objects)\nis not implemented yet.\n\n### Annotations\n\n[Annotations](https://docs.djangoproject.com/en/2.0/topics/db/aggregation/#aggregation)\nare not implemented yet.\n\n### Support other DBMS\n\nOracle is not supported at the moment because of they lack LIMIT clause\nin SELECT queries.\n\nMSSQL support development is stalled by [this issue](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/636).\nAs soon as it is fixed, development will be re-started.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiegojromerolopez%2Fbabik","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiegojromerolopez%2Fbabik","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiegojromerolopez%2Fbabik/lists"}