searchkon 0.1.1 → 1.0.3

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
  SHA256:
3
- metadata.gz: 5c3a98b95fd101cdff626be2a58c06db08136f252913bea0951de36291efc6f2
4
- data.tar.gz: 38a365ea4287172a83922d2cc44ba1a4cb4182be2376f0d0164ba09b7c27f936
3
+ metadata.gz: 8b03e8feb425ac126b0abc8d2e0684ba41f57a89e36373da2b7bb6e834b30841
4
+ data.tar.gz: 97bc80799ba817ba658ed2f259e8664c3ede624e419c8e5b317ecf195e8c6ece
5
5
  SHA512:
6
- metadata.gz: 973e2e6d10e9b0186487013ca5fa3ffc941875cd02f0a523703e2586cbf031394e8affb182405d4cd6456fb8e7a2d4f34387be5f97c1df3f4f413bb2e67914f8
7
- data.tar.gz: 1d225347ce400fe97012cc29f91beb753d0c0b5a3e39147553faa152170b359a35df88466cf88499a082f5ae641f1e0a7f7b81baaba7f3c46998b738a83b3794
6
+ metadata.gz: 1fe13d61e92bf189d2aa96db3f09efa587c4657fe712e870f57dc5340a371f77a016c81d886785c3be67f0ed5810a3b5755a6dfe9d96279d9ab8bc887a217ff5
7
+ data.tar.gz: b7eeb6ba941a093e1ec77826efe721eab29664147d006dca01a0f7abf877d9047e4e3401d8d72cb37ea88086433a1144db77e4f8e69d26b250b135de3ba56c39
data/Gemfile CHANGED
@@ -2,3 +2,5 @@
2
2
  source "http://rubygems.org"
3
3
 
4
4
  gemspec
5
+ gem 'activerecord', '~> 5.0', '>= 5.0.0.1'
6
+ gem 'activesupport', '~> 5.0', '>= 5.0.0.1'
data/README.md CHANGED
@@ -1 +1,143 @@
1
- Hello
1
+ # Searchkon
2
+
3
+ Searchkon is Advanced active record search(filter) command that makes easy to search throw models and their relationships.
4
+
5
+ ## Introduction
6
+
7
+ Lets say we want to return a list of products filtered by multiple parameters. our request contain below parameters:
8
+
9
+ ```
10
+ {
11
+ title: 'foobar',
12
+ id: [1, 2, 3, 4],
13
+ created_at: '(2012-12-21..2019-12-21)'
14
+ categories.name: 'mobile'
15
+ }
16
+
17
+ ```
18
+
19
+ Filter above parameters with Searchkon gem:
20
+
21
+ ```rb
22
+ Searchkon::QueryBuilder.filter('Product', filters)
23
+ ```
24
+
25
+ ## Getting Start
26
+
27
+
28
+ Add Searchkon to your Gemfile:
29
+ ```sh
30
+ gem 'searchkon'
31
+ ```
32
+
33
+ ### Searchable columns
34
+
35
+ at the first we should determine witch columns of model can be filter in Searchkon
36
+
37
+ ```rb
38
+ class Product < ActiveRecord::Base
39
+
40
+ has_many :coupons
41
+ has_many :payments
42
+
43
+ def self.searchable_columns
44
+ {
45
+ like: ['title', 'coupons.code'],
46
+ exact: [
47
+ 'created_at',
48
+ 'coupons.title', ## relational filter on coupons table
49
+ 'payments.id', ## relational filter on payments table
50
+ 'id'
51
+ ]
52
+ }
53
+ end
54
+ end
55
+
56
+ ```
57
+
58
+
59
+ <b> like: </b> if you add specific column in your like scope, your query will be like below sql.
60
+ ```sql
61
+ select * from products where title like %foo%
62
+ ```
63
+
64
+ <b>exact:</b> Searchkon create query using equal operation.
65
+
66
+ ```sql
67
+ select * from products where created_at = foo
68
+ ```
69
+
70
+ ### Simple where query
71
+
72
+ <b>Important: </b> Searchkon just accept filters key, you can add your filterable columns in filter key.
73
+
74
+
75
+ ```rb
76
+ params = {
77
+ id: 1,
78
+ title: 'foobar'
79
+ }
80
+ ```
81
+
82
+ ```rb
83
+ Searchkon::QueryBuilder.filter('Product', params)
84
+ ```
85
+
86
+ sql result:
87
+ ```sql
88
+ SELECT "products".* FROM "products" WHERE (products.title like '%foobar%') AND "products"."id" = 1
89
+ ```
90
+
91
+ ### Search Range
92
+
93
+ ```rb
94
+ params = {
95
+ id: '(1..10)',
96
+ created_at: '(2012-12-21..2019-12-21)'
97
+ }
98
+ ```
99
+
100
+ sql result:
101
+
102
+ ```sql
103
+ SELECT "products".* FROM "products" WHERE (products.title like '%foobar%') AND "products"."id" = 1
104
+ ```
105
+
106
+
107
+ ### Search in relational table
108
+
109
+
110
+ ```rb
111
+ params = {
112
+ 'coupons.id': [1,4,8]
113
+ }
114
+ ```
115
+
116
+ sql result:
117
+
118
+ ```sql
119
+ SELECT "products".* FROM "products" INNER JOIN "coupons" ON "coupons"."product_id" = "products"."id" WHERE "coupons"."id" IN (1, 4, 8)
120
+ ```
121
+
122
+
123
+ ### Invalid Column in query
124
+
125
+ if your filter parameters contain invalid column name, Searchkon skip it and create query without that column.
126
+
127
+ ```rb
128
+ invalid_mock_params = {
129
+ id: 1,
130
+ foo: 'foobar'
131
+ }
132
+ ```
133
+
134
+ ```rb
135
+ Searchkon::QueryBuilder.filter('Product', invalid_mock_params)
136
+ ```
137
+
138
+ sql result:
139
+
140
+
141
+ ```sql
142
+ SELECT "products".* FROM "products" WHERE "products"."id" = 1
143
+ ```
@@ -1,6 +1,6 @@
1
1
  module Searchkon
2
2
  module RegexFormatter
3
- SIMPLE_RANGE_FORMAT_REGEX = /\((.*)\.\.(.*)\)/
3
+ SIMPLE_RANGE_FORMAT_REGEX = /\((.*)\.\.(.*)\)/
4
4
  RELATIONAL_FORMAT_REGEX = /(.*)\.(.*)/
5
5
  DIGIT_RANGE_FORMAT_REGEX = /\((\d*)\.\.(\d*)\)/
6
6
  DATE_RANGE_FORMAT_REGEX = /\((\d{4}-\d{1,2}-\d{1,2})\.\.(\d{4}-\d{1,2}-\d{1,2})\)/
@@ -1,13 +1,13 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'searchkon'
3
- s.version = '0.1.1'
3
+ s.version = '1.0.3'
4
4
  s.date = '2020-05-24'
5
- s.summary = "Search Command"
6
- s.description = "make search easy"
7
- s.authors = ["Majid Imanzade"]
5
+ s.summary = "Advanced activerecord search/filter command"
6
+ s.description = "Advanced activerecord search/filter command"
7
+ s.authors = ["Majid Imanzade", 'Amin Samadzade']
8
8
  s.email = 'majidimanzade1@gmail.com'
9
- s.homepage = 'https://rubygems.org/gems/Helliot'
10
- s.homepage = "http://github.com/majidimanzade/Helliot"
9
+ s.homepage = 'https://rubygems.org/gems/searchkon'
10
+ s.homepage = "http://github.com/majidimanzade/searchkon"
11
11
  s.license = 'MIT'
12
12
 
13
13
  s.files = `git ls-files`.split("\n")
@@ -15,4 +15,8 @@ Gem::Specification.new do |s|
15
15
  s.add_development_dependency("bundler")
16
16
  s.add_development_dependency("rake")
17
17
  s.add_development_dependency("rspec")
18
+ s.add_development_dependency "sqlite3"
19
+
20
+ s.add_dependency "activesupport"
21
+ s.add_dependency "activerecord"
18
22
  end
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ class DummyClass
4
+ include Searchkon::RegexFormatter
5
+ include Searchkon::Filterable
6
+ end
7
+
8
+ RSpec.describe Searchkon::Filterable do
9
+ describe 'filterable test' do
10
+ it 'should return correct filter with scope' do
11
+ filrtetables = {
12
+ like: ['name', 'cities.name'],
13
+ exact: ['cities.id']
14
+ }
15
+ filters = {'cities.name,name': 'Don', 'cities.id': 1}
16
+ result = [{:value=>1, :key => "cities.id", :scope=>:exact},
17
+ {:value=>"Don", :key=> "cities.name,name", :scope=>:fulltext}]
18
+
19
+ dc = DummyClass.new
20
+
21
+ expect(dc.validate_params(filters, filrtetables)).to eq result
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ class Coupon < ActiveRecord::Base
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class Payment < ActiveRecord::Base
2
+
3
+ end
@@ -0,0 +1,17 @@
1
+ class Product < ActiveRecord::Base
2
+
3
+ has_many :coupons
4
+ has_many :payments
5
+
6
+ def self.searchable_columns
7
+ {
8
+ like: ['title', 'coupons.code'],
9
+ exact: [
10
+ 'created_at',
11
+ 'coupons.id',
12
+ 'payments.id',
13
+ 'id'
14
+ ]
15
+ }
16
+ end
17
+ end
@@ -0,0 +1,102 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ RSpec.describe Searchkon::QueryBuilder do
4
+ describe 'query builder for filter' do
5
+ let (:simple_where_params) do
6
+ {
7
+ id: 1,
8
+ title: 'foobar'
9
+ }
10
+ end
11
+
12
+ let (:simple_range_params) do
13
+ {
14
+ id: '(1..10)',
15
+ created_at: '(2012-12-21..2019-12-21)'
16
+ }
17
+ end
18
+
19
+ let (:range_and_array_where_params) do
20
+ {
21
+ id: [1,2,3,4,5],
22
+ created_at: '(2012-12-21..2019-12-21)'
23
+ }
24
+ end
25
+
26
+ it 'should return simple where query' do
27
+ query = "SELECT \"products\".* FROM \"products\" WHERE (products.title like '%foobar%') AND \"products\".\"id\" = 1"
28
+ expect(Searchkon::QueryBuilder.filter('Product', simple_where_params).to_sql).to eq query
29
+ end
30
+
31
+ it 'should return simple range query' do
32
+ query = "SELECT \"products\".* FROM \"products\" WHERE (products.created_at between '2012-12-21' and '2019-12-21') AND (products.id between '1' and '10')"
33
+
34
+ expect(Searchkon::QueryBuilder.filter('Product', simple_range_params).to_sql).to eq query
35
+ end
36
+
37
+ it 'should return simple where relational query' do
38
+ relational_params = { 'coupons.id': 1 }
39
+ query = "SELECT \"products\".* FROM \"products\" INNER JOIN \"coupons\" ON \"coupons\".\"product_id\" = \"products\".\"id\" WHERE \"coupons\".\"id\" = 1"
40
+
41
+ expect(Searchkon::QueryBuilder.filter('Product', relational_params).to_sql).to eq query
42
+ end
43
+
44
+ it 'should return range relational query' do
45
+ relational_params = { 'coupons.id': [1,2,3] }
46
+ query = "SELECT \"products\".* FROM \"products\" INNER JOIN \"coupons\" ON \"coupons\".\"product_id\" = \"products\".\"id\" WHERE \"coupons\".\"id\" IN (1, 2, 3)"
47
+
48
+ expect(Searchkon::QueryBuilder.filter('Product', relational_params).to_sql).to eq query
49
+ end
50
+
51
+ it 'should return simple where relational query with two relations' do
52
+ relational_params = { 'coupons.id': 1, 'payments.id': 1 }
53
+ query = "SELECT \"products\".* FROM \"products\" INNER JOIN \"coupons\" ON \"coupons\".\"product_id\" = \"products\".\"id\" INNER JOIN \"payments\" ON \"payments\".\"product_id\" = \"products\".\"id\" WHERE \"coupons\".\"id\" = 1 AND \"payments\".\"id\" = 1"
54
+ expect(Searchkon::QueryBuilder.filter('Product', relational_params).to_sql).to eq query
55
+ end
56
+
57
+ it 'should return range query and array where' do
58
+ query = "SELECT \"products\".* FROM \"products\" WHERE (products.created_at between '2012-12-21' and '2019-12-21') AND \"products\".\"id\" IN (1, 2, 3, 4, 5)"
59
+
60
+ expect(Searchkon::QueryBuilder.filter('Product', range_and_array_where_params).to_sql).to eq query
61
+ end
62
+
63
+ it 'should return all if params empty' do
64
+ query = "SELECT \"products\".* FROM \"products\""
65
+
66
+ expect(Searchkon::QueryBuilder.filter('Product', {}).to_sql).to eq query
67
+ end
68
+
69
+ it 'should raise error if model not exist' do
70
+ expect { Searchkon::QueryBuilder.filter('foobar', simple_where_params) }.to raise_error NameError
71
+ end
72
+
73
+ it 'should return all if all filter column not exist' do
74
+ query = "SELECT \"products\".* FROM \"products\""
75
+ invalid_mock_params = {
76
+ blah: 1,
77
+ foo: 'foobar'
78
+ }
79
+
80
+ expect(Searchkon::QueryBuilder.filter('Product', invalid_mock_params).to_sql).to eq query
81
+ end
82
+
83
+ it 'should return query if one filter column not exist' do
84
+ query = "SELECT \"products\".* FROM \"products\" WHERE \"products\".\"id\" = 1"
85
+ some_invalid_mock_params = {
86
+ id: 1,
87
+ foo: 'foobar'
88
+ }
89
+
90
+ expect(Searchkon::QueryBuilder.filter('Product', some_invalid_mock_params).to_sql).to eq query
91
+ end
92
+
93
+ it 'should return fulltext query if params has fulltext key' do
94
+ query = "SELECT \"products\".* FROM \"products\" INNER JOIN \"coupons\" ON \"coupons\".\"product_id\" = \"products\".\"id\" WHERE (products.title like '%foobar%' or coupons.code like '%foobar%')"
95
+ params = {
96
+ 'title,coupons.code': 'foobar'
97
+ }
98
+
99
+ expect(Searchkon::QueryBuilder.filter('Product', params).to_sql).to eq query
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,20 @@
1
+ ActiveRecord::Schema.define do
2
+ self.verbose = false
3
+
4
+ create_table :products, :force => true do |t|
5
+ t.string :key
6
+ t.string :title
7
+ t.timestamps
8
+ end
9
+
10
+ create_table :coupons, :force => true do |t|
11
+ t.string :title
12
+ t.timestamps
13
+ end
14
+
15
+ create_table :payments, :force => true do |t|
16
+ t.string :title
17
+ t.timestamps
18
+ end
19
+
20
+ end
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'searchkon'
5
+ require 'active_record'
6
+ require 'active_support'
7
+ require 'active_support/core_ext'
8
+ require 'rspec'
9
+
10
+ ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
11
+
12
+ load File.dirname(__FILE__) + '/schema.rb'
13
+ require File.dirname(__FILE__) + '/models/coupon.rb'
14
+ require File.dirname(__FILE__) + '/models/payment.rb'
15
+ require File.dirname(__FILE__) + '/models/product.rb'
metadata CHANGED
@@ -1,10 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchkon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Majid Imanzade
8
+ - Amin Samadzade
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
@@ -52,7 +53,49 @@ dependencies:
52
53
  - - ">="
53
54
  - !ruby/object:Gem::Version
54
55
  version: '0'
55
- description: make search easy
56
+ - !ruby/object:Gem::Dependency
57
+ name: sqlite3
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: activesupport
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: activerecord
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description: Advanced activerecord search/filter command
56
99
  email: majidimanzade1@gmail.com
57
100
  executables: []
58
101
  extensions: []
@@ -62,14 +105,20 @@ files:
62
105
  - Gemfile
63
106
  - LICENSE
64
107
  - README.md
65
- - elliot-0.0.1.gem
66
108
  - lib/searchkon.rb
67
109
  - lib/searchkon/filterable.rb
68
110
  - lib/searchkon/query_builder.rb
69
111
  - lib/searchkon/regex_formatter.rb
70
112
  - lib/searchkon/searchables.rb
71
113
  - searchkon.gemspec
72
- homepage: http://github.com/majidimanzade/Helliot
114
+ - spec/filterable_spec.rb
115
+ - spec/models/coupon.rb
116
+ - spec/models/payment.rb
117
+ - spec/models/product.rb
118
+ - spec/query_builder_spec.rb
119
+ - spec/schema.rb
120
+ - spec/spec_helper.rb
121
+ homepage: http://github.com/majidimanzade/searchkon
73
122
  licenses:
74
123
  - MIT
75
124
  metadata: {}
@@ -91,5 +140,5 @@ requirements: []
91
140
  rubygems_version: 3.1.2
92
141
  signing_key:
93
142
  specification_version: 4
94
- summary: Search Command
143
+ summary: Advanced activerecord search/filter command
95
144
  test_files: []