index_query_builder 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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