{"id":13394975,"url":"https://github.com/activerecord-hackery/squeel","last_synced_at":"2025-12-16T22:42:52.758Z","repository":{"id":45803239,"uuid":"1591828","full_name":"activerecord-hackery/squeel","owner":"activerecord-hackery","description":"Active Record, improved. Live again :)","archived":true,"fork":false,"pushed_at":"2022-03-29T17:18:31.000Z","size":622,"stargazers_count":2399,"open_issues_count":82,"forks_count":213,"subscribers_count":53,"default_branch":"master","last_synced_at":"2024-10-29T22:52:42.249Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://erniemiller.org/2013/11/17/anyone-interested-in-activerecord-hackery/","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/activerecord-hackery.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2011-04-09T15:41:39.000Z","updated_at":"2024-10-15T22:51:35.000Z","dependencies_parsed_at":"2022-07-17T10:16:21.140Z","dependency_job_id":null,"html_url":"https://github.com/activerecord-hackery/squeel","commit_stats":null,"previous_names":["ernie/squeel"],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/activerecord-hackery%2Fsqueel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/activerecord-hackery%2Fsqueel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/activerecord-hackery%2Fsqueel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/activerecord-hackery%2Fsqueel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/activerecord-hackery","download_url":"https://codeload.github.com/activerecord-hackery/squeel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234583683,"owners_count":18856280,"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-07-30T17:01:37.963Z","updated_at":"2025-09-29T02:32:30.407Z","avatar_url":"https://github.com/activerecord-hackery.png","language":"Ruby","readme":"# Archived\n\nThis project is archived.\n\n\n# Squeel [![Build Status](https://secure.travis-ci.org/activerecord-hackery/squeel.png)](http://travis-ci.org/activerecord-hackery/squeel) [![endorse](http://api.coderwall.com/ernie/endorsecount.png)](http://coderwall.com/ernie)\n\nSqueel lets you write your Active Record queries with fewer strings, and more Ruby,\nby making the Arel awesomeness that lies beneath Active Record more accessible.\n\nSqueel lets you rewrite...\n\n```ruby\nArticle.where ['created_at \u003e= ?', 2.weeks.ago]\n```\n\n...as...\n\n```ruby\nArticle.where{created_at \u003e= 2.weeks.ago}\n```\n\nThis is a _good thing_. If you don't agree, Squeel might not be for you. The above is\njust a simple example -- Squeel's capable of a whole lot more. Keep reading.\n\n## Getting started\n\nIn your Gemfile:\n\n```ruby\ngem \"squeel\"  # Last officially released gem\n# gem \"squeel\", :git =\u003e \"git://github.com/activerecord-hackery/squeel.git\" # Track git repo\n```\n\nThen bundle as usual.\n\nIf you'd like to customize Squeel's functionality by enabling core\nextensions for hashes or symbols, or aliasing some predicates, you can\ncreate a sample initializer with:\n\n```sh\n$ rails g squeel:initializer\n```\n\n## The Squeel Query DSL\n\nSqueel enhances the normal Active Record query methods by enabling them to accept\nblocks. Inside a block, the Squeel query DSL can be used. Note the use of curly braces\nin these examples instead of parentheses. `{}` denotes a Squeel DSL query.\n\nStubs and keypaths are the two primary building blocks used in a Squeel DSL query, so we'll\nstart by taking a look at them. Most of the other examples that follow will be based on\nthis \"symbol-less\" block syntax.\n\n**An important gotcha, before we begin:** The Squeel DSL works its magic using `instance_eval`.\nIf you've been working with Ruby for a while, you'll know immediately that this means that\n_inside_ a Squeel DSL block, `self` isn't the same thing that it is _outside_ the block.\n\nThis carries with it an important implication: \u003cstrong\u003eInstance variables and instance methods\ninside the block won't refer to your object's variables/methods.\u003c/strong\u003e\n\nDon't worry, Squeel's got you covered. Use one of the following methods to get access\nto your object's methods and variables:\n\n  1. Assign the variable locally before the DSL block, and access it as you would\n     normally.\n  2. Supply an arity to the DSL block, as in `Person.where{|q| q.name == @my_name}`\n     Downside: You'll need to prefix stubs, keypaths, and functions (explained below)\n     with the DSL object.\n  3. Wrap the method or instance variable inside the block with `my{}`.\n     `Person.where{name == my{some_method_to_return_a_name}}`\n\n### Stubs\n\nStubs are, for most intents and purposes, just like Symbols in a normal call to\n`Relation#where` (note the need for doubling up on the curly braces here, the first ones\nstart the block, the second are the hash braces):\n\n```ruby\nPerson.where{{name =\u003e 'Ernie'}}\n# =\u003e SELECT \"people\".* FROM \"people\"  WHERE \"people\".\"name\" = 'Ernie'\n```\n\nYou normally wouldn't bother using the DSL in this case, as a simple hash would\nsuffice. However, stubs serve as a building block for keypaths, and keypaths are\nvery handy.\n\n### KeyPaths\n\nA Squeel keypath is essentially a more concise and readable alternative to a\ndeeply nested hash. For instance, in standard Active Record, you might join several\nassociations like this to perform a query:\n\n```ruby\nPerson.joins(:articles =\u003e {:comments =\u003e :person})\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    INNER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\n#    INNER JOIN \"comments\" ON \"comments\".\"article_id\" = \"articles\".\"id\"\n#    INNER JOIN \"people\" \"people_comments\" ON \"people_comments\".\"id\" = \"comments\".\"person_id\"\n```\n\nWith a keypath, this would look like:\n\n```ruby\nPerson.joins{articles.comments.person}\n```\n\nA keypath can exist in the context of a hash, and is normally interpreted relative to\nthe current level of nesting. It can be forced into an \"absolute\" path by anchoring it with\na ~, like:\n\n```ruby\n~articles.comments.person\n```\n\nThis isn't quite so useful in the typical hash context, but can be very useful when it comes\nto interpreting functions and the like. We'll cover those later.\n\n### Predicates\n\nAll of the Arel \"predication\" methods can be accessed inside the Squeel DSL, via\ntheir method name, an alias, or an an operator, to create Arel predicates, which are\nused in `WHERE` or `HAVING` clauses.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eSQL\u003c/th\u003e\n    \u003cth\u003ePredication\u003c/th\u003e\n    \u003cth\u003eOperator\u003c/th\u003e\n    \u003cth\u003eAlias\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e=\u003c/td\u003e\n    \u003ctd\u003eeq\u003c/td\u003e\n    \u003ctd\u003e==\u003c/td\u003e\n    \u003ctd\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e!=\u003c/td\u003e\n    \u003ctd\u003enot_eq\u003c/td\u003e\n    \u003ctd\u003e!= (1.9 only), ^ (1.8)\u003c/td\u003e\n    \u003ctd\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003eLIKE\u003c/td\u003e\n    \u003ctd\u003ematches\u003c/td\u003e\n    \u003ctd\u003e=~\u003c/td\u003e\n    \u003ctd\u003elike\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003eNOT LIKE\u003c/td\u003e\n    \u003ctd\u003edoes_not_match\u003c/td\u003e\n    \u003ctd\u003e!~ (1.9 only)\u003c/td\u003e\n    \u003ctd\u003enot_like\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u0026lt;\u003c/td\u003e\n    \u003ctd\u003elt\u003c/td\u003e\n    \u003ctd\u003e\u0026lt;\u003c/td\u003e\n    \u003ctd\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u0026lt;=\u003c/td\u003e\n    \u003ctd\u003elteq\u003c/td\u003e\n    \u003ctd\u003e\u0026lt;=\u003c/td\u003e\n    \u003ctd\u003elte\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003e\u003c/td\u003e\n    \u003ctd\u003egt\u003c/td\u003e\n    \u003ctd\u003e\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003e=\u003c/td\u003e\n    \u003ctd\u003egteq\u003c/td\u003e\n    \u003ctd\u003e\u003e=\u003c/td\u003e\n    \u003ctd\u003egte\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003eIN\u003c/td\u003e\n    \u003ctd\u003ein\u003c/td\u003e\n    \u003ctd\u003e\u003e\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003eNOT IN\u003c/td\u003e\n    \u003ctd\u003enot_in\u003c/td\u003e\n    \u003ctd\u003e\u0026lt;\u0026lt;\u003c/td\u003e\n    \u003ctd\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nLet's say we want to generate this simple query:\n\n```\nSELECT \"people\".* FROM people WHERE \"people\".\"name\" = 'Joe Blow'\n```\n\nAll of the following will generate the above SQL:\n\n```ruby\nPerson.where(:name =\u003e 'Joe Blow')\nPerson.where{{name =\u003e 'Joe Blow'}}\nPerson.where{{name.eq =\u003e 'Joe Blow'}}\nPerson.where{name.eq 'Joe Blow'}\nPerson.where{name == 'Joe Blow'}\n```\n\nNot a very exciting example since equality is handled just fine via the\nfirst example in standard Active Record. But consider the following query:\n\n```sql\nSELECT \"people\".* FROM people\nWHERE (\"people\".\"name\" LIKE 'Ernie%' AND \"people\".\"salary\" \u003c 50000)\n  OR  (\"people\".\"name\" LIKE 'Joe%' AND \"people\".\"salary\" \u003e 100000)\n```\n\nTo do this with standard Active Record, we'd do something like:\n\n```ruby\nPerson.where(\n  '(name LIKE ? AND salary \u003c ?) OR (name LIKE ? AND salary \u003e ?)',\n  'Ernie%', 50000, 'Joe%', 100000\n)\n```\n\nWith Squeel:\n\n```ruby\nPerson.where{(name =~ 'Ernie%') \u0026 (salary \u003c 50000) | (name =~ 'Joe%') \u0026 (salary \u003e 100000)}\n```\n\nHere, we're using `\u0026` and `|` to generate `AND` and `OR`, respectively.\n\nThere are two obvious but important differences between these two code samples, and\nboth of them have to do with *context*.\n\n1. To read code with SQL interpolation, the structure of the SQL query must\n   first be considered, then we must cross-reference the values to be substituted\n   with their placeholders. This carries with it a small but perceptible (and\n   annoying!) context shift during which we stop thinking about the comparison being\n   performed, and instead play \"count the arguments\", or, in the case of\n   named/hash interpolations, \"find the word\". The Squeel syntax places\n   both sides of each comparison in proximity to one another, allowing us to\n   focus on what our code is doing.\n\n2. In the first example, we're starting off with Ruby, switching context to SQL,\n   and then back to Ruby, and while we spend time in SQL-land, we're stuck with\n   SQL syntax, whether or not it's the best way to express what we're trying to do.\n   With Squeel, we're writing Ruby from start to finish. And with Ruby syntax comes\n   flexibility to express the query in the way we see fit.\n\n### Predicate aliases\n\nThat last bit is important. We can mix and match predicate methods with operators\nand take advantage of Ruby's operator precedence or parenthetical grouping to make\nour intentions more clear, on the first read-through. And if we don't like the\nway that the existing predications read, we can create our own aliases in a Squeel\nconfigure block:\n\n```ruby\nSqueel.configure do |config|\n  config.alias_predicate :is_less_than, :lt\nend\n```\n```ruby\nPerson.where{salary.is_less_than 50000}.to_sql\n# =\u003e SELECT \"people\".* FROM \"people\"  WHERE \"people\".\"salary\" \u003c 50000\n```\n\nAnd while we're on the topic of helping you make your code more expressive...\n\n### Compound conditions\n\nLet's say you want to check if a Person has a name like one of several possibilities.\n\n```ruby\nnames = ['Ernie%', 'Joe%', 'Mary%']\nPerson.where('name LIKE ? OR name LIKE ? OR name LIKE ?', *names)\n```\n\nBut you're smart, and you know that you might want to check more or less than\n3 names, so you make your query flexible:\n\n```ruby\nPerson.where((['name LIKE ?'] * names.size).join(' OR '), *names)\n```\n\nYeah... that's readable, all right. How about:\n\n```ruby\nPerson.where{name.like_any names}\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    WHERE ((\"people\".\"name\" LIKE 'Ernie%' OR \"people\".\"name\" LIKE 'Joe%' OR \"people\".\"name\" LIKE 'Mary%'))\n```\n\nI'm not sure about you, but I much prefer the latter. In short, you can add `_any` or\n`_all` to any predicate method, and it would do what you expect, when given an array of\npossibilities to compare against.\n\n### Sifters\n\nSifters are like little snippets of conditions that take parameters. Let's say that you\nhave a model called Article, and you often want to query for articles that contain a\nstring in the title or body. So you write a scope:\n\n```ruby\ndef self.title_or_body_contains(string)\n  where{title.matches(\"%#{string}%\") | body.matches(\"%#{string}%\")}\nend\n```\n\nBut then you want to query for people who wrote an article that matches these conditions,\nbut the scope only works against the model where it was defined. So instead, you write a\nsifter:\n\n```ruby\nclass Article \u003c ActiveRecord::Base\n  sifter :title_or_body_contains do |string|\n    title.matches(\"%#{string}%\") | body.matches(\"%#{string}%\")\n  end\nend\n```\n\nNow you can write...\n\n```ruby\nArticle.where{sift :title_or_body_contains, 'awesome'}\n# =\u003e SELECT \"articles\".* FROM \"articles\"\n#    WHERE ((\n#      \"articles\".\"title\" LIKE '%awesome%'\n#      OR \"articles\".\"body\" LIKE '%awesome%'\n#    ))\n```\n\n... or ...\n\n```ruby\nPerson.joins(:articles).\n       where{\n         {articles =\u003e sift(:title_or_body_contains, 'awesome')}\n       }\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    INNER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\n#    WHERE ((\n#      \"articles\".\"title\" LIKE '%awesome%'\n#      OR \"articles\".\"body\" LIKE '%awesome%'\n#    ))\n```\n\nOr, you can just modify your previous scope, changing `where` to `squeel`:\n\n```ruby\ndef self.title_or_body_contains(string)\n  squeel{title.matches(\"%#{string}%\") | body.matches(\"%#{string}%\")}\nend\n```\n\n### Subqueries\n\nYou can supply an `ActiveRecord::Relation` as a value for a predicate in order to use\na subquery. So, for example:\n\n```ruby\nawesome_people = Person.where{awesome == true}\nArticle.where{author_id.in(awesome_people.select{id})}\n# =\u003e SELECT \"articles\".* FROM \"articles\"\n#    WHERE \"articles\".\"author_id\" IN (SELECT \"people\".\"id\" FROM \"people\"  WHERE \"people\".\"awesome\" = 't')\n```\n\n### Joins\n\nSqueel adds a couple of enhancements to joins. First, keypaths can be used as shorthand for\nnested association joins. Second, you can specify join types (inner and outer), and a class\nin the case of a polymorphic belongs_to relationship.\n\n```ruby\nPerson.joins{articles.outer}\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    LEFT OUTER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\nNote.joins{notable(Person).outer}\n# =\u003e SELECT \"notes\".* FROM \"notes\"\n#    LEFT OUTER JOIN \"people\"\n#      ON \"people\".\"id\" = \"notes\".\"notable_id\"\n#      AND \"notes\".\"notable_type\" = 'Person'\n```\n\nThese can also be used inside keypaths:\n\n```ruby\nNote.joins{notable(Person).articles}\n# =\u003e SELECT \"notes\".* FROM \"notes\"\n#    INNER JOIN \"people\" ON \"people\".\"id\" = \"notes\".\"notable_id\"\n#      AND \"notes\".\"notable_type\" = 'Person'\n#    INNER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\n```\n\nYou can refer to these associations when constructing other parts of your query, and\nthey'll be automatically mapped to the proper table or table alias This is most noticeable\nwhen using self-referential associations:\n\n```ruby\nPerson.joins{children.parent.children}.\n       where{\n         (children.name.like 'Ernie%') |\n         (children.parent.name.like 'Ernie%') |\n         (children.parent.children.name.like 'Ernie%')\n       }\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    INNER JOIN \"people\" \"children_people\" ON \"children_people\".\"parent_id\" = \"people\".\"id\"\n#    INNER JOIN \"people\" \"parents_people\" ON \"parents_people\".\"id\" = \"children_people\".\"parent_id\"\n#    INNER JOIN \"people\" \"children_people_2\" ON \"children_people_2\".\"parent_id\" = \"parents_people\".\"id\"\n#    WHERE (((\"children_people\".\"name\" LIKE 'Ernie%'\n#          OR \"parents_people\".\"name\" LIKE 'Ernie%')\n#          OR \"children_people_2\".\"name\" LIKE 'Ernie%'))\n```\n\nKeypaths were used here for clarity, but nested hashes would work just as well.\n\nYou can also use a subquery in a join.\n\nNotice:\n1. Squeel can only accept an ActiveRecord::Relation class of subqueries in a join.\n2. Use the chain with caution. You should call `as` first to get a Nodes::As, then call `on` to get a join node.\n\n```ruby\nsubquery = OrderItem.group(:orderable_id).select { [orderable_id, sum(quantity * unit_price).as(amount)] }\nSeat.joins { [payment.outer, subquery.as('seat_order_items').on { id == seat_order_items.orderable_id}.outer] }.\n              select { [seat_order_items.amount, \"seats.*\"] }\n# =\u003e SELECT \"seat_order_items\".\"amount\", seats.*\n#    FROM \"seats\"\n#    LEFT OUTER JOIN \"payments\" ON \"payments\".\"id\" = \"seats\".\"payment_id\"\n#    LEFT OUTER JOIN (\n#      SELECT \"order_items\".\"orderable_id\",\n#             sum(\"order_items\".\"quantity\" * \"order_items\".\"unit_price\") AS amount\n#      FROM \"order_items\"\n#      GROUP BY \"order_items\".\"orderable_id\"\n#    ) seat_order_items ON \"seats\".\"id\" = \"seat_order_items\".\"orderable_id\"\n```\n\n### Includes\n\nIncludes works similarly with joins, it uses outer join defaultly. In Rails 4,\nyou need to use `references` with `includes` together.\n\n#### Rails 4+\n\n```ruby\nPerson.includes(:articles =\u003e {:comments =\u003e :person}).references(:all)\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    LEFT OUTER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\n#    LEFT OUTER JOIN \"comments\" ON \"comments\".\"article_id\" = \"articles\".\"id\"\n#    LEFT OUTER JOIN \"people\" \"people_comments\" ON \"people_comments\".\"id\" = \"comments\".\"person_id\"\n```\n\nWith a keypath, this would look like:\n\n```ruby\nPerson.includes{articles.comments.person}.references(:all)\n```\n\n#### Rails 3.x\n\n```ruby\nPerson.includes(:articles =\u003e {:comments =\u003e :person})\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    LEFT OUTER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\n#    LEFT OUTER JOIN \"comments\" ON \"comments\".\"article_id\" = \"articles\".\"id\"\n#    LEFT OUTER JOIN \"people\" \"people_comments\" ON \"people_comments\".\"id\" = \"comments\".\"person_id\"\n```\n\nWith a keypath, this would look like:\n\n```ruby\nPerson.includes{articles.comments.person}\n```\n\n### Functions\n\nYou can call SQL functions just like you would call a method in Ruby...\n\n```ruby\nPerson.select{coalesce(name, '\u003cno name given\u003e')}\n# =\u003e SELECT coalesce(\"people\".\"name\", '\u003cno name given\u003e') FROM \"people\"\n```\n\n...and you can easily give it an alias:\n\n```ruby\nperson = Person.select{\n  coalesce(name, '\u003cno name given\u003e').as(name_with_default)\n}.first\nperson.name_with_default # name or \u003cno name given\u003e, depending on data\n```\n\nWhen you use a stub, symbol, or keypath inside a function call, it'll be interpreted relative to\nits place inside any nested associations:\n\n```ruby\nPerson.joins{articles}.group{articles.title}.having{{articles =\u003e {max(id) =\u003e id}}}\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    INNER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\n#    GROUP BY \"articles\".\"title\"\n#    HAVING max(\"articles\".\"id\") = \"articles\".\"id\"\n```\n\nIf you want to use an attribute from a different branch of the hierarchy, use an absolute\nkeypath (~) as done here:\n\n```ruby\nPerson.joins{articles}.group{articles.title}.having{{articles =\u003e {max(~id) =\u003e id}}}\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    INNER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\n#    GROUP BY \"articles\".\"title\"\n#    HAVING max(\"people\".\"id\") = \"articles\".\"id\"\n```\n\n### SQL Operators\n\nYou can use the standard mathematical operators (`+`, `-`, `*`, `/`) inside the Squeel DSL to\nspecify operators in the resulting SQL, or the `op` method to specify another\ncustom operator, such as the standard SQL concatenation operator, `||`:\n\n```ruby\np = Person.select{name.op('||', '-diddly').as(flanderized_name)}.first\np.flanderized_name\n# =\u003e \"Aric Smith-diddly\"\n```\n\nAs you can see, just like functions, these operations can be given aliases.\n\nTo select more than one attribute (or calculated attribute) simply put them into an array:\n\n```ruby\np = Person.select{[ name.op('||', '-diddly').as(flanderized_name),\n                    coalesce(name, '\u003cno name given\u003e').as(name_with_default) ]}.first\np.flanderized_name\n# =\u003e \"Aric Smith-diddly\"\np.name_with_default\n# =\u003e \"Aric Smith\"\n```\n\n\n## Compatibility with Active Record\n\nMost of the new functionality provided by Squeel is accessed with the new block-style `where{}`\nsyntax.\n\nAll your existing code that uses plain Active Record `where()` queries should continue to work the\nsame after adding Squeel to your project with one exception: symbols as the value side of a\ncondition (in normal `where()` clauses).\n\n### Symbols as the value side of a condition (in normal `where()` clauses)\n\nIf you have any `where()` clauses that use a symbol as the value side\n(right-hand side) of a condition, **you will need to change the symbol into a\nstring in order for it to continue to be treated as a value**.\n\nSqueel changes the meaning of symbols in the value of a condition to refer to\nthe name of a **column** instead of simply treating the symbol as a **string literal**.\n\nFor example, this query:\n\n```ruby\nPerson.where(:first_name =\u003e :last_name)\n```\n\nproduces this SQL query in plain Active Record:\n\n```sql\nSELECT people.* FROM people WHERE people.first_name = 'last_name'.\n```\n\nbut produces this SQL query if you are using Squeel:\n\n```sql\nSELECT people.* FROM people WHERE people.first_name = people.last_name\n```\n\nNote that this new behavior applies to the plain `where()`-style expressions in addition to the new\n`where{}` Squeel style.\n\nIn order for your existing  `where()` clauses with symbols to continue to behave the same, you\n**must** change the symbols into strings. These scopes, for example:\n\n```ruby\nscope :active, where(:state =\u003e :active)\nscope :in_state, lambda {|state| where(:state =\u003e state) }\n```\n\nshould be changed to this:\n\n```ruby\nscope :active, where(:state =\u003e 'active')\nscope :in_state, lambda {|state| where(:state =\u003e state.to_s) }\n```\n\nFor further information, see\n[this post to the Rails list](https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-core/NQJJzZ7R7S0),\n[this commit](https://github.com/lifo/docrails/commit/50c5005bafe7e43f81a141cd2c512379aec74325) to\nthe [Active Record guides](http://edgeguides.rubyonrails.org/active_record_querying.html#hash-conditions),\n[#67](https://github.com/activerecord-hackery/squeel/issues/67),\n[#75](https://github.com/activerecord-hackery/squeel/issues/75), and\n[#171](https://github.com/activerecord-hackery/squeel/issues/171).\n\n## Compatibility with MetaWhere\n\nWhile the Squeel DSL is the preferred way to access advanced query functionality, you can\nstill enable methods on symbols to access Arel predications in a similar manner to MetaWhere:\n\n```ruby\nSqueel.configure do |config|\n  config.load_core_extensions :symbol\nend\n```\n```ruby\nPerson.joins(:articles =\u003e :comments).\n       where(:articles =\u003e {:comments =\u003e {:body.matches =\u003e 'Hello!'}})\n# =\u003e SELECT \"people\".* FROM \"people\"\n#    INNER JOIN \"articles\" ON \"articles\".\"person_id\" = \"people\".\"id\"\n#    INNER JOIN \"comments\" ON \"comments\".\"article_id\" = \"articles\".\"id\"\n#    WHERE \"comments\".\"body\" LIKE 'Hello!'\n```\n\nThis should help to smooth over the transition to the new DSL.\n\n## Contributions\n\nIf you'd like to support the continued development of Squeel, please consider\n[making a donation](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=N7QP5N3UB76ME).\n\nTo support the project in other ways:\n\n* Use Squeel in your apps, and let me know if you encounter anything that's broken or missing.\n  A failing spec is awesome. A pull request is even better!\n* Spread the word on Twitter, Facebook, and elsewhere if Squeel's been useful to you. The more\n  people who are using the project, the quicker we can find and fix bugs!\n\n## Copyright\n\nCopyright \u0026copy; 2011 [Ernie Miller](http://twitter.com/erniemiller)\n","funding_links":["https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=N7QP5N3UB76ME"],"categories":["Ruby","Gems"],"sub_categories":["ActiveRecord"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Factiverecord-hackery%2Fsqueel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Factiverecord-hackery%2Fsqueel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Factiverecord-hackery%2Fsqueel/lists"}