index_query_builder 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8af5c5d595d2eadb2940a4f1aaea38103970502e
4
- data.tar.gz: a7a3cec53023cfab0ca2fb6b3fd0f37d1c81a910
3
+ metadata.gz: 3ea38e4a701413196312ab11d0477be169272c3b
4
+ data.tar.gz: 59431b3ac8e08468b91469a04eb79206355093a7
5
5
  SHA512:
6
- metadata.gz: ca1644edcd841d1acd9b393538959bab3c5df58eababc66db5d8780ec32c4edf60c1b25cd4ae2f89d5e364af75a568b09b8c5c026c46d2deef7b1f06d8a27506
7
- data.tar.gz: 559fa403af8cf4f64845f49d0c8f858bd4ab10746a5297272344f0bbcf8eb4e95dcb5990d8cae03baba79eeee11f9c928a572d40deb4f7096e3f391188a39f9a
6
+ metadata.gz: a107eef8cd790695cf35a119e4e145a28bc312d5f20df41a90b62926231d99c22182487b0b6ba4b4f3c31f39f093e629fb5cc2f97a508d37cd8c3781a7ecff2e
7
+ data.tar.gz: 55ce20fbdda01589d68161cb43164aeb1ea7c3deb958c910c14d33d80579fb3cb61fff6494358a8b09eb8e650ee98afdb33eff29701257a5c6406de8bebc633d
@@ -0,0 +1,13 @@
1
+ root = true
2
+
3
+ [*]
4
+
5
+ indent_style = space
6
+ indent_size = 2
7
+ end_of_line = lf
8
+ charset = utf-8
9
+ trim_trailing_whitespace = true
10
+ insert_final_newline = true
11
+
12
+ [*.md]
13
+ trim_trailing_whitespace = false
data/.gitignore CHANGED
@@ -48,3 +48,5 @@ build-iPhoneSimulator/
48
48
 
49
49
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
50
  .rvmrc
51
+
52
+ config/database.yml
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- index_query_builder (0.0.1)
4
+ index_query_builder (0.0.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -49,13 +49,13 @@ PLATFORMS
49
49
  ruby
50
50
 
51
51
  DEPENDENCIES
52
- activerecord (~> 4.0.0)
53
- activesupport (~> 4.0.0)
52
+ activerecord (~> 4.0, >= 4.0.0)
53
+ activesupport (~> 4.0, >= 4.0.0)
54
54
  bundler (~> 1.7)
55
55
  index_query_builder!
56
56
  pg (~> 0.18.1)
57
57
  rake (~> 10.0)
58
- rspec (~> 3.3.0)
58
+ rspec (~> 3.3, >= 3.3.0)
59
59
 
60
60
  BUNDLED WITH
61
- 1.11.2
61
+ 1.12.5
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # IndexQueryBuilder
2
2
 
3
- TODO: Write a gem description
3
+ This gem provides a DSL on top of ActiveRecord to get collection of models for index pages with filters.
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,17 +20,93 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ Let's say you have the following schema:
24
+
25
+ ```ruby
26
+ create_table :posts, force: true do |t|
27
+ t.text :title
28
+ t.integer :view_count
29
+ end
30
+
31
+ create_table :comments, force: true do |t|
32
+ t.integer :post_id
33
+ t.text :text
34
+ end
35
+ ```
36
+
37
+ And the following models
38
+
39
+ ```ruby
40
+ class Post < ActiveRecord::Base
41
+ has_many :comments
42
+ end
43
+
44
+ class Comment < ActiveRecord::Base
45
+ belongs_to :post
46
+ end
47
+ ```
48
+
49
+ And you are building an index page for posts with the following requirements:
50
+ * Posts should be ordered by `view_count`.
51
+ * The user should be able to filter posts by texts in post's comments. For example, if `filters` is `{ comment_text: 'This post is amazing' }`, then we should return all the posts with a comment containing `'This post is amazing'`.
52
+ * More filters will be added soon.
53
+
54
+ Without Index Query Builder, you will probably have to do something like this.
55
+
56
+ ```ruby
57
+ conditions_strings = []
58
+ conditions_params = {}
59
+
60
+ unless filters[:comment_text].blank?
61
+ conditions_strings << "comments.text ILIKE :comment_text"
62
+ conditions_params[:comment_text] = "%#{filters[:comment_text]}%"
63
+ end
64
+
65
+ conditions = (conditions_params.empty? ? "" : [conditions_strings.join(" AND "), conditions_params])
66
+
67
+ joins_list = []
68
+ joins_list << {:posts => :comment} if filters[:comment_text].present?
69
+
70
+ posts = Post.where(conditions).joins(joins_list).order("expected_ship_at desc, id desc")
71
+ ```
72
+
73
+ Or, with Index Query Builder, you can just write this.
74
+
75
+ ```ruby
76
+ posts = IndexQueryBuilder.query Post, with: filters do |query|
77
+ query.filter_field [:comments, :text], contains: :comment_text
78
+ query.order_by "view_count DESC"
79
+ end
80
+ ```
81
+
82
+ ## Operators
83
+
84
+ Operators will apply where clauses to query *only if* the filter_name is present in filters hash.
85
+
86
+ * :equal_to applies field_name = filter_value
87
+ * :contains applies substring (ILIKE '%filter_value%')
88
+ * :greater_than_or_equal_to applies field_name >= filter_value
89
+ * :less_than applies field_name < filter_value
90
+ * :present_if applies:
91
+ * field_name IS NOT NULL if filter_value
92
+ * field_name IS NULL if !filter_value
93
+
94
+ Find more in the [docs](http://www.rubydoc.info/gems/index_query_builder)
24
95
 
25
96
  ## Running tests
26
97
 
27
- $ cd bounded_contexts/index_query_builder
98
+ It requires PostgreSQL.
99
+
100
+ $ cp config/database.yml.sample config/database.yml
101
+
102
+ Update `config/database.yml` with your connection information.
103
+
28
104
  $ rake db:test:setup
29
105
  $ rspec
30
106
 
31
107
  ## Contributing
32
108
 
33
- 1. Fork it ( https://github.com/[my-github-username]/index_query_builder/fork )
109
+ 1. Fork it ( https://github.com/arturopie/index_query_builder/fork )
34
110
  2. Create your feature branch (`git checkout -b my-new-feature`)
35
111
  3. Commit your changes (`git commit -am 'Add some feature'`)
36
112
  4. Push to the branch (`git push origin my-new-feature`)
@@ -6,8 +6,8 @@ require "index_query_builder/version"
6
6
 
7
7
  # Simple DSL for building queries using filters.
8
8
  #
9
- # This module makes it easy to fetch records from the database, specially
10
- # for showing and filtering records in an index page
9
+ # This module makes it easy to fetch records from the database, specially
10
+ # for showing and filtering records in an index page
11
11
  #
12
12
  module IndexQueryBuilder
13
13
 
@@ -16,21 +16,20 @@ module IndexQueryBuilder
16
16
  # @param base_scope [Arel] used to build query on top of this scope
17
17
  # @param options [Hash]
18
18
  # @option :with [Hash] filters used to build query. Key is filter name, value is value for the filter
19
- # @param &block yield to build query using IndexQueryBuilder's DSL
19
+ # @yield [QueryDefinition] Gives a QueryDefinition object that implements a DSL to define how to apply filters
20
20
  # @return [Arel] returns arel object to make it easy to extend query (e.g. add pagination, etc)
21
21
  #
22
22
  # ==== Example
23
23
  #
24
- # receive_orders = IndexQueryBuilder.query ReceiveOrder.where(:site_id => site.id), with: { sku_code: 'ABC' } do |query|
25
- # query.filter_field :received
26
- # query.filter_field :reference, contains: :reference
27
- # query.filter_field :expected_delivery_at,
28
- # greater_than_or_equal_to: :from_expected_delivery_at, less_than: :to_expected_delivery_at
29
- # query.filter_field [:receive_order_items, :sku, :code], equal_to: :sku_code
30
- #
31
- # query.order_by "expected_delivery_at DESC, receive_orders.id DESC"
32
- # end
24
+ # posts = IndexQueryBuilder.query Post.where(:user_id => user.id), with: { title: 'DSLs are awesome' } do |query|
25
+ # query.filter_field :posted
26
+ # query.filter_field :title, contains: :title
27
+ # query.filter_field :posted_date,
28
+ # greater_than_or_equal_to: :from_posted_date, less_than: :to_posted_date
29
+ # query.filter_field [:comments, :author, :name], equal_to: :comment_author_name
33
30
  #
31
+ # query.order_by "posted_date DESC, posts.created_at DESC"
32
+ # end
34
33
  def self.query(base_scope, options={}, &block)
35
34
  query_definition = QueryDefinition.new
36
35
  block.call(query_definition)
@@ -46,21 +45,20 @@ module IndexQueryBuilder
46
45
  # @param base_scope [Arel] used to build query on top of this scope
47
46
  # @param options [Hash]
48
47
  # @option options [Hash] :with filters used to build query. Key is filter name, value is value for the filter
49
- # @param &block yield to build query using IndexQueryBuilder's DSL
48
+ # @yield [QueryDefinition] Gives a QueryDefinition object that implements a DSL to define how to apply filters
50
49
  # @return [Arel] returns arel object to make it easy to extend query (e.g. add pagination, etc)
51
50
  #
52
51
  # ==== Example
53
52
  #
54
- # receive_order_items = IndexQueryBuilder.query_children :receive_order_items, ReceiveOrder.scoped_by(site), with: filters do |query|
55
- # query.filter_field :received
56
- # query.filter_field :reference, contains: :reference
57
- # query.filter_field :expected_delivery_at,
58
- # greater_than_or_equal_to: :from_expected_delivery_at, less_than: :to_expected_delivery_at
59
- # query.filter_field [:receive_order_items, :sku, :code], equal_to: :sku_code
60
- #
61
- # query.order_by "expected_delivery_at DESC, receive_orders.id DESC"
62
- # end
53
+ # comments = IndexQueryBuilder.query_children :comments, Comments, with: { title: 'DSLs are awesome' } do |query|
54
+ # query.filter_field :posted
55
+ # query.filter_field :title, contains: :title
56
+ # query.filter_field :posted_date,
57
+ # greater_than_or_equal_to: :from_posted_date, less_than: :to_posted_date
58
+ # query.filter_field [:comments, :author, :name], equal_to: :comment_author_name
63
59
  #
60
+ # query.order_by "comment_date DESC"
61
+ # end
64
62
  def self.query_children(child_association, base_scope, options={}, &block)
65
63
  parents = query(base_scope.eager_load(child_association), options, &block)
66
64
 
@@ -18,30 +18,30 @@ module IndexQueryBuilder
18
18
  #
19
19
  # ==== Operators
20
20
  #
21
- # Operators will apply where clauses to query *only if* the filter_name is present in filters hash.
21
+ # Operators will apply where clauses to query only if the filter_name is present in filters hash.
22
22
  #
23
23
  # [:equal_to]
24
- # Applies field_name = filter_value
24
+ # Applies 'field_name = filter_value'
25
25
  # [:contains]
26
26
  # Applies substring (ILIKE '%filter_value%')
27
27
  # [:greater_than_or_equal_to]
28
- # Applies field_name >= filter_value
28
+ # Applies 'field_name >= filter_value'
29
29
  # [:less_than]
30
- # Applies field_name < filter_value
30
+ # Applies 'field_name < filter_value'
31
31
  # [:present_if]
32
32
  # Applies
33
- # field_name IS NOT NULL if filter_value
34
- # field_name IS NULL if filter_value
33
+ # * 'field_name IS NOT NULL' if filter_value is truthy
34
+ # * 'field_name IS NULL' if filter_value is falsey
35
35
  #
36
36
  # === Examples
37
37
  #
38
- # <tt>query.filter_field :received</tt>
39
- # <tt>query.filter_field :reference, contains: :reference</tt>
40
- # <tt>query.filter_field [:vendor, :name], equal_to: :vendor_name</tt>
41
- # <tt>query.filter_field [:receive_order_items, :sku, :code], equal_to: :sku_code</tt>
42
- # <tt>query.filter_field :expected_delivery_at, greater_than_or_equal_to: :from_expected_delivery_at, less_than: :to_expected_delivery_at</tt>
43
- # <tt>query.filter_field :expected_delivery_at, less_than_or_equal_to: :to_expected_delivery_at</tt>
44
- # <tt>query.filter_field :outbound_trailer_id, present_if: :has_trailer</tt>
38
+ # query.filter_field :received
39
+ # query.filter_field :reference, contains: :reference
40
+ # query.filter_field [:vendor, :name], equal_to: :vendor_name
41
+ # query.filter_field [:receive_order_items, :sku, :code], equal_to: :sku_code
42
+ # query.filter_field :expected_delivery_at, greater_than_or_equal_to: :from_expected_delivery_at, less_than: :to_expected_delivery_at
43
+ # query.filter_field :expected_delivery_at, less_than_or_equal_to: :to_expected_delivery_at
44
+ # query.filter_field :outbound_trailer_id, present_if: :has_trailer
45
45
  #
46
46
  def filter_field(field_name, predicates={equal_to: field_name})
47
47
  predicates.each do |operator, filter|
@@ -1,3 +1,3 @@
1
1
  module IndexQueryBuilder
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -4,15 +4,15 @@ require 'integration_spec_helper'
4
4
  RSpec.describe IndexQueryBuilder do
5
5
  describe 'operator :contains' do
6
6
  it 'returns records containing filter value' do
7
- Post.create!(title: "Using Rubymine because it's awesome")
8
- Post.create!(title: "VIM is useless")
7
+ Post.create!(title: "This is a post I love")
8
+ Post.create!(title: "This is another post")
9
9
 
10
- posts = IndexQueryBuilder.query Post.where(nil), with: { title: 'Rubymine' } do |query|
10
+ posts = IndexQueryBuilder.query Post.where(nil), with: { title: 'love' } do |query|
11
11
  query.filter_field :title, contains: :title
12
12
  end
13
13
 
14
14
  expect(posts.length).to eq(1)
15
- expect(posts[0].title).to eq("Using Rubymine because it's awesome")
15
+ expect(posts[0].title).to eq("This is a post I love")
16
16
  end
17
17
 
18
18
  it 'filters using association' do
@@ -28,15 +28,15 @@ RSpec.describe IndexQueryBuilder do
28
28
 
29
29
  describe 'operator :equal_to' do
30
30
  it 'returns records equal to filter value' do
31
- Post.create!(title: "Using Rubymine because it's awesome")
32
- Post.create!(title: "VIM is useless")
31
+ Post.create!(title: "This is a post I love")
32
+ Post.create!(title: "This is another post")
33
33
 
34
- posts = IndexQueryBuilder.query Post.where(nil), with: { title: "Using Rubymine because it's awesome" } do |query|
34
+ posts = IndexQueryBuilder.query Post.where(nil), with: { title: "This is a post I love" } do |query|
35
35
  query.filter_field :title, equal_to: :title
36
36
  end
37
37
 
38
38
  expect(posts.length).to eq(1)
39
- expect(posts[0].title).to eq("Using Rubymine because it's awesome")
39
+ expect(posts[0].title).to eq("This is a post I love")
40
40
  end
41
41
 
42
42
  it 'filters using association' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: index_query_builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arturo Pie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-09 00:00:00.000000000 Z
11
+ date: 2016-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -120,12 +120,14 @@ executables: []
120
120
  extensions: []
121
121
  extra_rdoc_files: []
122
122
  files:
123
+ - ".editorconfig"
123
124
  - ".gitignore"
125
+ - ".rspec"
124
126
  - Gemfile
125
127
  - Gemfile.lock
126
128
  - README.md
127
129
  - Rakefile
128
- - config/database.yml
130
+ - config/database.yml.sample
129
131
  - index_query_builder.gemspec
130
132
  - lib/index_query_builder.rb
131
133
  - lib/index_query_builder/query_builder.rb