LogicalQueryParser

A parser to generate a tree structure from a logical search query string using treetop.

Dependencies

  • ruby 2.3+
  • treetop 1.6+
  • activerecord 4.2+ (optional)

Installation

Add this line to your application’s Gemfile:

ruby gem 'logical_query_parser'

And then execute:

$ bundle

Or install it yourself as:

$ gem install logical_query_parser

Usage

You can parse a logical query string as follows:

```ruby parser = LogicalQueryParser.new parser.parse(‘a AND b’)

return value is a syntax tree of treetop

=> SyntaxNode+Exp0+ExpNode offset=0, “a AND b” (any): SyntaxNode+Cond0+CondNode offset=0, “a AND b” (lexp,logic,rexp): SyntaxNode+Literal0+LiteralNode offset=0, “a” (word,negative): SyntaxNode offset=0, “” SyntaxNode+WordNode offset=0, “a”: SyntaxNode+Atom0 offset=0, “a”: SyntaxNode offset=0, “” SyntaxNode offset=0, “a” SyntaxNode offset=1, “ “: SyntaxNode offset=1, “ “ SyntaxNode+AndNode offset=2, “AND” SyntaxNode offset=5, “ “: SyntaxNode offset=5, “ “ SyntaxNode+Exp0+ExpNode offset=6, “b” (any): SyntaxNode+Literal0+LiteralNode offset=6, “b” (word,negative): SyntaxNode offset=6, “” SyntaxNode+WordNode offset=6, “b”: SyntaxNode+Atom0 offset=6, “b”: SyntaxNode offset=6, “” SyntaxNode offset=6, “b” ```

You can parse quoted strings:

parser = LogicalQueryParser.new parser.parse('("a a" AND "b b") OR (c AND d)')

You can also parse negative conditions:

parser = LogicalQueryParser.new parser.parse('("a a" AND NOT "b b") OR (c AND -d)')

Supported operators

  • AND / and / &: represents an AND logic.
  • OR / or / : represents an OR logic.
  • NOT / -: represents a NOT logic. This should precede to a word or a parenthesis.
  • (: represents beginning of a nested expression.
  • ): represents end of a nested expression.
  • ”: represents beginning or end of a quoted word.
  • Space: represents a boundary between two words.

For more information, see grammar definition.

Use with ActiveRecord

You can use a syntax tree to compile a SQL statement for activerecord. For example:

```ruby class Doc < ActiveRecord::Base end

LogicalQueryParser.search(“a AND b”, Doc.all, :c1, :c2).to_sql # SELECT “docs”.* FROM “docs” # WHERE ((“docs”.”c1” LIKE ‘%a%’ OR “docs”.”c2” LIKE ‘%a%’) AND (“docs”.”c1” LIKE ‘%b%’ OR “docs”.”c2” LIKE ‘%b%’)) ```

Use with associations:

```ruby class Doc < ActiveRecord::Base has_many :tags end

class Tag < ActiveRecord::Base end

LogicalQueryParser.search(“a AND b”, Doc.all, :c1, :c2, tags: [:c3]).to_sql # SELECT “docs”.* FROM “docs” # INNER JOIN “tags” ON “tags”.”doc_id” = “docs”.”id” # WHERE (((“docs”.”c1” LIKE ‘%a%’ OR “docs”.”c2” LIKE ‘%a%’) OR “tags”.”c3” LIKE ‘%a%’) AND # ((“docs”.”c1” LIKE ‘%b%’ OR “docs”.”c2” LIKE ‘%b%’) OR “tags”.”c3” LIKE ‘%b%’)) ```

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/kanety/logical_query_parser.

License

The gem is available as open source under the terms of the MIT License.