clearly-query 0.3.1.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +8 -0
  3. data/.gitignore +42 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +10 -0
  6. data/CHANGELOG.md +43 -0
  7. data/Gemfile +7 -0
  8. data/Guardfile +19 -0
  9. data/LICENSE +22 -0
  10. data/README.md +102 -0
  11. data/Rakefile +7 -0
  12. data/SPEC.md +101 -0
  13. data/bin/guard +16 -0
  14. data/bin/rake +16 -0
  15. data/bin/rspec +16 -0
  16. data/bin/yard +16 -0
  17. data/clearly-query.gemspec +33 -0
  18. data/lib/clearly/query.rb +22 -0
  19. data/lib/clearly/query/cleaner.rb +63 -0
  20. data/lib/clearly/query/compose/comparison.rb +102 -0
  21. data/lib/clearly/query/compose/conditions.rb +215 -0
  22. data/lib/clearly/query/compose/core.rb +75 -0
  23. data/lib/clearly/query/compose/custom.rb +268 -0
  24. data/lib/clearly/query/compose/range.rb +114 -0
  25. data/lib/clearly/query/compose/special.rb +24 -0
  26. data/lib/clearly/query/compose/subset.rb +115 -0
  27. data/lib/clearly/query/composer.rb +269 -0
  28. data/lib/clearly/query/definition.rb +165 -0
  29. data/lib/clearly/query/errors.rb +27 -0
  30. data/lib/clearly/query/graph.rb +63 -0
  31. data/lib/clearly/query/helper.rb +50 -0
  32. data/lib/clearly/query/validate.rb +296 -0
  33. data/lib/clearly/query/version.rb +8 -0
  34. data/spec/lib/clearly/query/cleaner_spec.rb +42 -0
  35. data/spec/lib/clearly/query/compose/custom_spec.rb +77 -0
  36. data/spec/lib/clearly/query/composer_query_spec.rb +50 -0
  37. data/spec/lib/clearly/query/composer_spec.rb +422 -0
  38. data/spec/lib/clearly/query/definition_spec.rb +23 -0
  39. data/spec/lib/clearly/query/graph_spec.rb +81 -0
  40. data/spec/lib/clearly/query/helper_spec.rb +17 -0
  41. data/spec/lib/clearly/query/version_spec.rb +7 -0
  42. data/spec/spec_helper.rb +89 -0
  43. data/spec/support/db/migrate/001_db_create.rb +62 -0
  44. data/spec/support/models/customer.rb +63 -0
  45. data/spec/support/models/order.rb +66 -0
  46. data/spec/support/models/part.rb +63 -0
  47. data/spec/support/models/product.rb +67 -0
  48. data/spec/support/shared_setup.rb +13 -0
  49. data/tmp/.gitkeep +0 -0
  50. metadata +263 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d045cfa5f732a083d9a8b102bd7c2cdd67b24722
4
+ data.tar.gz: 8c486d7e7add811d6898ac9d695fa2981b108e21
5
+ SHA512:
6
+ metadata.gz: 25e62009d801425f4f18a5955bc88656f6fab91ba071653b398caa0221abc8f2420c0ba48969dcf6289715e9a88580bc5a62cd08c5de2d1eada28bcfd63dc308
7
+ data.tar.gz: b9604376d04f1f49ac70a4b01267af962a7607fa03e03f9e28b702484c26975636a59c9ee350e7660a93d5bc9a206cc791b2df32c706ea770003f71f4f2409ca
data/.codeclimate.yml ADDED
@@ -0,0 +1,8 @@
1
+ engines:
2
+ rubocop:
3
+ enabled: true
4
+ ratings:
5
+ paths:
6
+ - "**.rb"
7
+ exclude_paths:
8
+ - spec/**/*
data/.gitignore ADDED
@@ -0,0 +1,42 @@
1
+ *.gem
2
+ *.rbc
3
+ *.bundle
4
+ *.so
5
+ *.o
6
+ *.a
7
+ mkmf.log
8
+ /.config
9
+ /coverage/
10
+ /InstalledFiles
11
+ /pkg/
12
+ /spec/reports/
13
+ /test/tmp/
14
+ /test/version_tmp/
15
+ /tmp/*
16
+ !/tmp/.gitkeep
17
+ /.idea/
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+
24
+ ## Documentation cache and generated files:
25
+ /.yardoc/
26
+ /_yardoc/
27
+ /doc/
28
+ /rdoc/
29
+
30
+ ## Environment normalisation:
31
+ /.bundle/
32
+ /vendor/bundle
33
+ /lib/bundler/man/
34
+
35
+ # for a library or gem, you might want to ignore these files since the code is
36
+ # intended to run in multiple environments; otherwise, check them in:
37
+ /Gemfile.lock
38
+ .ruby-version
39
+ .ruby-gemset
40
+
41
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
42
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ cache: bundler
3
+ sudo: false
4
+ rvm:
5
+ - 2.2.3
6
+ script:
7
+ - bin/rspec
8
+ addons:
9
+ code_climate:
10
+ repo_token: 7f46a15011c053c6e456e9ad33bcf9a7a22277fe99107996721dfd2ae301a38b
data/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ Non-trivial changes will be documented here.
4
+ This project adheres to [Semantic Versioning](http://semver.org/)
5
+ and [keeps a change log](http://keepachangelog.com/) (you're reading it!).
6
+
7
+ ## Unreleased
8
+
9
+ ## Release [v0.3.1-pre](https://github.com/cofiem/clearly-query/releases/tag/v0.3.1-pre) (2015-11-01)
10
+
11
+ ### Added
12
+ - new DFS graph traversal for calculating joins between tables
13
+ - additional tests for Composer
14
+
15
+ ### Changed
16
+ - composer and definition functionality redistributed to be more obvious and have simpler methods
17
+
18
+ ## Release [v0.2.0-pre](https://github.com/cofiem/clearly-query/releases/tag/0.2.0) (2015-10-27)
19
+
20
+ ### Added
21
+
22
+ - Transported hash filter modules and classes from [baw-server](https://github.com/QutBioacoustics/baw-server)
23
+ - Created change log
24
+
25
+ ## Change log categories
26
+
27
+ ### Added
28
+ new features
29
+
30
+ ### Changed
31
+ changes in existing functionality
32
+
33
+ ### Deprecated
34
+ once-stable features removed in upcoming releases
35
+
36
+ ### Removed
37
+ deprecated features removed in this release
38
+
39
+ ### Fixed
40
+ bug fixes
41
+
42
+ ### Security
43
+ vulnerabilities or other problems that should be highlighted
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in clearly/query.gemspec
4
+ gemspec
5
+
6
+ # for reporting code coverage to code climate
7
+ gem 'codeclimate-test-reporter', group: :test, require: nil
data/Guardfile ADDED
@@ -0,0 +1,19 @@
1
+ guard :rspec, cmd: 'bin/rspec' do
2
+ require 'guard/rspec/dsl'
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # RSpec files
6
+ rspec = dsl.rspec
7
+ watch(rspec.spec_helper) { rspec.spec_dir }
8
+ watch(rspec.spec_support) { rspec.spec_dir }
9
+ watch(rspec.spec_files)
10
+
11
+ # Ruby files
12
+ ruby = dsl.ruby
13
+ dsl.watch_spec_files_for(ruby.lib_files)
14
+
15
+ end
16
+
17
+ guard :yard, cmd: 'bin/yard doc' do
18
+ watch(%r{lib/.+\.rb})
19
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Mark
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # Clearly Query
2
+
3
+ A library for constructing an sql query from a hash.
4
+
5
+ Uses [Arel](https://github.com/rails/arel) and [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord).
6
+
7
+ ## Project Status
8
+
9
+ [![Build Status](https://travis-ci.org/cofiem/clearly-query.svg?branch=master)](https://travis-ci.org/cofiem/clearly-query)
10
+ [![Dependency Status](https://gemnasium.com/cofiem/clearly-query.svg)](https://gemnasium.com/cofiem/clearly-query)
11
+ [![Code Climate](https://codeclimate.com/github/cofiem/clearly-query/badges/gpa.svg)](https://codeclimate.com/github/cofiem/clearly-query)
12
+ [![Test Coverage](https://codeclimate.com/github/cofiem/clearly-query/badges/coverage.svg)](https://codeclimate.com/github/cofiem/clearly-query/coverage)
13
+ [![Documentation Status](https://inch-ci.org/github/cofiem/clearly-query.svg?branch=master)](https://inch-ci.org/github/cofiem/clearly-query)
14
+ [![Documentation](https://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/github/cofiem/clearly-query)
15
+ [![Join the chat at https://gitter.im/cofiem/clearly-query](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cofiem/clearly-query?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ gem 'clearly-query'
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install clearly-query
30
+
31
+ ## Usage
32
+
33
+ There are two main public classes in this gem.
34
+ The Definition class makes use of a settings declared in a model.
35
+ The Composer converts a hash of options into an Arel query.
36
+
37
+ ### [Clearly::Query::Definition](./lib/clearly/query/definition.rb)
38
+
39
+ Contains the query specification for ActiveRecord models.
40
+
41
+ For example:
42
+
43
+ Clearly::Query::Definition.new(Customer, Customer.clearly_query_def)
44
+
45
+ and
46
+
47
+ # model/customer.rb
48
+ def self.clearly_query_def
49
+ {
50
+ fields: {
51
+ valid: [:name, :last_contact_at],
52
+ text: [:name],
53
+ mappings: [
54
+ {
55
+ name: :title,
56
+ value: Clearly::Query::Helper.string_concat(
57
+ Customer.arel_table[:name],
58
+ Arel::Nodes.build_quoted(' title'))
59
+ }
60
+ ]
61
+ },
62
+ associations: [
63
+ {
64
+ join: Order,
65
+ on: Order.arel_table[:customer_id].eq(Customer.arel_table[:id]),
66
+ available: true,
67
+ associations: []
68
+ }
69
+ ],
70
+ defaults: {
71
+ order_by: :created_at,
72
+ direction: :desc
73
+ }
74
+ }
75
+ end
76
+
77
+ ### [Clearly::Query::Composer](./lib/clearly/query/composer.rb)
78
+
79
+ Constructs an Arel query from a hash of options.
80
+ See the [query hash specification](SPEC.md) for a comprehensive overview.
81
+
82
+ For example:
83
+
84
+ composer = Clearly::Query::Composer.from_active_record
85
+ query_hash = {and: {name: {contains: 'test'}}} # from e.g. HTTP request
86
+ cleaned_query_hash = Clearly::Query::Cleaner.new.do(query_hash)
87
+ model = Customer
88
+ conditions = composer.query(model, cleaned_query_hash)
89
+ query = model.where(conditions)
90
+
91
+ ## Contributing
92
+
93
+ 1. [Fork this repo](https://github.com/cofiem/clearly-query/fork)
94
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
95
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
96
+ 4. Push to the branch (`git push origin my-new-feature`)
97
+ 5. Create a new [pull request](https://github.com/cofiem/clearly-query/compare)
98
+
99
+ ## More Information about Arel
100
+
101
+ - [Using Arel to Compose SQL Queries](http://robots.thoughtbot.com/using-arel-to-compose-sql-queries)
102
+ - [The definitive guide to Arel, the SQL manager for Ruby](http://jpospisil.com/2014/06/16/the-definitive-guide-to-arel-the-sql-manager-for-ruby.html)
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
data/SPEC.md ADDED
@@ -0,0 +1,101 @@
1
+ # Query Hash Specification
2
+
3
+ Inspired by [elastic search filters](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-filters.html).
4
+
5
+ ## Available Filter Operators
6
+
7
+ ### Combine Operators
8
+
9
+ Operator | Query hash | SQL
10
+ ----------|----------------|---------------------
11
+ and | {and: { ... }} | WHERE ... AND ...
12
+ or | {or: { ... }} | WHERE ... OR (...)
13
+ not | {not: { ... }} | WHERE ... NOT (...)
14
+
15
+ Implicit `and` is used when no combine operator is specified.
16
+
17
+ ### Filter Operators
18
+
19
+ Filter comparison operator has multiple forms to help with constructing queries that read more 'naturally'.
20
+ Be aware that it is possible operators may be 'case sensitive by default
21
+ for unicode characters that are beyond the ASCII range'. For example, in [sqlite](https://www.sqlite.org/lang_expr.html).
22
+
23
+ #### Comparison Operators
24
+
25
+ Comparison operators are self-explanatory.
26
+
27
+ Operator | Query hash | SQL
28
+ -------------------------------------|----------------------------|---------------------------------
29
+ eq, equal | {attr: {eq: 'test'}} | "table"."attr" = 'test'
30
+ not_eq, not_equal | {attr: {not_eq: 'test'}} | "table"."attr" != 'test'
31
+ lt, less_than | {attr: {lt: 'test'}} | "table"."attr" < 'test'
32
+ not_lt, not_less_than | {attr: {not_lt: 'test'}} | "table"."attr" >= 'test'
33
+ gt, greater_than | {attr: {gt: 'test'}} | "table"."attr" > 'test'
34
+ not_gt, not_greater_than | {attr: {not_gt: 'test'}} | "table"."attr" <= 'test'
35
+ lteq, less_than_or_equal | {attr: {lteq: 'test'}} | "table"."attr" <= 'test'
36
+ not_lteq, not_less_than_or_equal | {attr: {not_lteq: 'test'}} | "table"."attr" > 'test'
37
+ gteq, greater_than_or_equal | {attr: {gteq: 'test'}} | "table"."attr" >= 'test'
38
+ not_gteq, not_greater_than_or_equal | {attr: {not_gteq: 'test'}} | "table"."attr" < 'test'
39
+
40
+ #### Special Comparisons
41
+
42
+ There are special operators for `null` comparisons.
43
+ The only valid values for these operators is `true` or `false`.
44
+ Any other value is invalid.
45
+
46
+ Operator | Query hash | SQL
47
+ -----------------------|----------------------------|---------------------------------
48
+ null, is_null | {attr: {null: true}} | "table"."attr" IS NULL
49
+
50
+ #### Subset Operators
51
+
52
+ ##### Range
53
+
54
+ A simple range is inclusive lower bound and exclusive upper bound.
55
+
56
+ Operator | Query hash | SQL
57
+ ------------------------|-----------------------------------------------------|------------------------------------------------------------------
58
+ range, in_range | {attr: {range: {from: 'value1', to: 'value2'}}} | "table"."attr" >= 'value1' AND "table"."attr" < 'value2'
59
+ not_range, not_in_range | {attr: {not_range: {from: 'value1', to: 'value2'}}} | ("table"."attr" > 'value1' OR "table"."attr" >= 'value2')
60
+
61
+ A more complex range can be specified using a regex which allows for inclusive or exclusive bounds.
62
+
63
+ Operator | Query hash | SQL
64
+ -------------|---------------------------------------|----------------------------------------------------------
65
+ interval | {attr: {interval: '(value1,value2]'}} | "table"."attr" > 'value1' AND "table"."attr" <= 'value2'
66
+ not_interval | {attr: {interval: '(value1,value2]'}} | ("table"."attr" <= 'value1' OR "table"."attr" > 'value2')
67
+
68
+ The `interval` must match the regex `/(\[|\()(.*),(.*)(\)|\])/`
69
+ where `(` or `)` indicates exclusive and `[` or `]` indicates inclusive.
70
+ Specifying `[value1,value2]` is equivalent to `BETWEEN value1 AND value2`.
71
+
72
+ Any spaces between the brackets will be included in the value.
73
+ The result of including commas (`,`) in either value is undefined.
74
+
75
+ ##### Arrays
76
+
77
+ An array of values to match the attribute value exactly.
78
+
79
+ Operator | Query hash | SQL
80
+ ---------|-------------------------------------|-----------------------------------------------
81
+ in | {attr: {in: ['value1,value2']}} | "table"."attr" IN ('value1', 'value2')
82
+ not_in | {attr: {not_in: ['value1,value2']}} | "table"."attr" NOT IN ('value1', 'value2')
83
+
84
+ ##### Contents Match
85
+
86
+ Match the contents of a model attributes.
87
+ These comparison operators are case insensitive where possible (usually depends on database).
88
+ It is possible to match at the entire content, at the start of the content, or at the end.
89
+
90
+ Regular expression match **may not be supported by all databases**.
91
+
92
+ Operator | Query hash | SQL
93
+ ------------------------------------------------------|-----------------------------------|-----------------------------------------------
94
+ contains, contain | {attr: {contain: 'value'}} | "table"."attr" LIKE 'value'
95
+ not_contains, not_contain, does_not_contain | {attr: {not_contain: 'value'}} | "table"."attr" NOT LIKE 'value'
96
+ starts_with, start_with | {attr: {start_with: 'value'}} | "table"."attr" LIKE 'value%'
97
+ not_starts_with,not_start_with, does_not_start_with | {attr: {not_start_with: 'value'}} | "table"."attr" NOT LIKE 'value%'
98
+ ends_with, end_with | {attr: {end_with: 'value'}} | "table"."attr" LIKE '%value'
99
+ not_ends_with, not_end_with, does_not_end_with | {attr: {not_end_with: 'value'}} | "table"."attr" NOT LIKE '%value'
100
+ regex, regex_match, matches, match | {attr: {regex: 'value'}} | "table"."attr" SIMILAR TO 'value'
101
+ not_regex, not_regex_match, does_not_match, not_match | {attr: {not_end_with: 'value'}} | "table"."attr" NOT SIMILAR TO 'value'
data/bin/guard ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'guard' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('guard', 'guard')
data/bin/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
data/bin/rspec ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'rspec')