saringan 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 14714e62396c119de8d76254c91fdb1eba523c4042ed0b267f6c85722addf6f6
4
+ data.tar.gz: ae2440972f2ac820a684fb744d29838ff8b67ea21e5e7221382c362e656828a4
5
+ SHA512:
6
+ metadata.gz: '0272149bca14917ce4e26e692124d620db706f42ee322121387da38151c6ed6c29ae3ca1b1963c7cf44bc9f3758c931f2bdfa7bef341b4e25e2d1d2d2d35a921'
7
+ data.tar.gz: 55f23a72543de8a5e1989ba37f5f29e1c12a185096e185f95f59c0e8e9881a6f4ca05d3406c1e8df82aeaf479d321ea3c27bd4b0fcd37ef35da851633fdcceb3
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 TODO: Write your name
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Saringan
2
+
3
+ Translate query strings to activerecord query parameters.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'saringan'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install saringan
20
+
21
+ ## Usage
22
+
23
+ Use Saringan::Translator to translate query string to activerecord parameters:
24
+
25
+ ```ruby
26
+ irb> query = "name::John"
27
+ irb> Saringan::Translator.translate(query)
28
+ { name: 'John' }
29
+ ```
30
+
31
+ ### Operators
32
+
33
+ **Obs.:** This is a preliminar version, so others operators will be implemented in future versions.
34
+
35
+ #### Equals
36
+
37
+ This handle absolute equals query like "WHERE name = 'John'".
38
+ To do it you must use Saringan equals operator '::'
39
+
40
+ In URL: http://site.com?query=name::John
41
+
42
+ In code:
43
+ ```ruby
44
+ irb> query = params[:query]
45
+ irb> Saringan::Translator.translate(query)
46
+ { name: 'John' }
47
+ ```
48
+
49
+ ### Parsers
50
+
51
+ **Obs.:** This is a preliminar version, so others parsers will be implemented in future versions.
52
+
53
+ #### String Parser
54
+
55
+ Just pass value without any qualifier
56
+
57
+ #### Date Time Parser
58
+
59
+ Pass value using Saringan Date Time qualifier.
60
+ Saringan will parse value to DateTime object. It expect date time in '%Y-%m-%d %H:%M:%S' format, see:
61
+
62
+ In URL: http://site.com?query=starts_at::dt[2018-06-30 00:00:00]
63
+
64
+ In code:
65
+ ```ruby
66
+ irb> query = params[:query]
67
+ irb> Saringan::Translator.translate(query)
68
+ { starts_at: DateTime object }
69
+ ```
70
+
71
+ ##### Range
72
+
73
+ Pass value using Saringan range operator '|'
74
+
75
+ In URL: http://site.com?query=starts_at::dt[2018-06-30 00:00:00|2018-06-30 23:59:59]
76
+
77
+ In code:
78
+ ```ruby
79
+ irb> query = params[:query]
80
+ irb> Saringan::Translator.translate(query)
81
+ { starts_at: DateTime object..DateTime object }
82
+ ```
83
+
84
+ ## License
85
+
86
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,17 @@
1
+ require 'saringan/operators'
2
+
3
+ module Saringan
4
+ class Operator
5
+ class << self
6
+ def parse(term)
7
+ return equal.to_h(term) if equal.match?(term)
8
+ end
9
+
10
+ private
11
+
12
+ def equal
13
+ Saringan::Operators::Equal
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ require 'saringan/parser'
2
+
3
+ module Saringan
4
+ module Operators
5
+ class Equal
6
+
7
+ OP_EQUAL = /::/
8
+
9
+ class << self
10
+ def to_h(term)
11
+ splitted = split(term)
12
+ { "#{splitted[:key]}": parser.parse(splitted[:value]) }
13
+ end
14
+
15
+ def to_query(term)
16
+ splitted = split(term)
17
+ { query: "#{splitted[:key]} = ?", params: splitted[:value] }
18
+ end
19
+
20
+ def match?(term)
21
+ term =~ OP_EQUAL
22
+ end
23
+
24
+ def split(term)
25
+ splitted = term.split(OP_EQUAL)
26
+ { key: splitted[0], value: splitted[1] }
27
+ end
28
+
29
+ private
30
+
31
+ def parser
32
+ Saringan::Parser
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1 @@
1
+ require 'saringan/operators/equal'
@@ -0,0 +1,28 @@
1
+ require 'saringan/parsers'
2
+
3
+ module Saringan
4
+ class Parser
5
+ class << self
6
+ def parse(value)
7
+ return range.to_h(value) if range.match?(value)
8
+ return datetime_range_parser(value) if date_time_range.match?(value)
9
+ value
10
+ end
11
+
12
+ def datetime_range_parser(value)
13
+ values = date_time_range.to_h(value)
14
+ values[:from]..values[:to]
15
+ end
16
+
17
+ private
18
+
19
+ def range
20
+ Saringan::Parsers::Range
21
+ end
22
+
23
+ def date_time_range
24
+ Saringan::Parsers::DateTimeRange
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require 'active_support/core_ext/time'
3
+ require 'active_support/core_ext/date_time'
4
+
5
+ module Saringan
6
+ module Parsers
7
+ class DateTimeRange < Range
8
+ MATCHER = /^dt\[(.+)\]$/
9
+ FORMAT = '%Y-%m-%d %H:%M:%S'
10
+
11
+ class << self
12
+ def split(value)
13
+ splitted = super(value)
14
+ splitted.map do |part|
15
+ date = DateTime.strptime(part, FORMAT)
16
+ DateTime.new date.year, date.month, date.day, date.hour, date.min, \
17
+ date.sec, DateTime.current.zone
18
+ end
19
+ end
20
+
21
+ def clean(value)
22
+ value.gsub(/^dt\[/, '').gsub(/\]$/, '')
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ module Saringan
2
+ module Parsers
3
+ class IntegerRange < Range
4
+ MATCHER = /^i\[(.+)\]$/
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ module Saringan
5
+ module Parsers
6
+ class Range
7
+ MATCHER = /^\[(.+)\]$/
8
+
9
+ class << self
10
+ def match?(value)
11
+ value =~ matcher
12
+ end
13
+
14
+ def to_h(value)
15
+ splitted = split(value)
16
+ { from: parse_value(splitted[0]), to: parse_value(splitted[1]) }
17
+ end
18
+
19
+ def split(value)
20
+ cleaned = clean(value)
21
+ cleaned.split('|')
22
+ end
23
+
24
+ def clean(value)
25
+ value.gsub(/^\[/, '').gsub(/\]$/, '')
26
+ end
27
+
28
+ def parse_value(value)
29
+ value
30
+ end
31
+
32
+ private
33
+
34
+ def matcher
35
+ self::MATCHER
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,4 @@
1
+ require 'saringan/parsers/range'
2
+ require 'saringan/parsers/date_time_range'
3
+
4
+ require 'saringan/parser'
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ module Saringan
5
+ class Term
6
+ TERM_SEP = ','
7
+
8
+ OP_N_EQUAL_S = /:!:/
9
+ OP_N_EQUAL_I = /:<>:/
10
+ OP_LESS = /:<:/
11
+ OP_BIGGER = /:>:/
12
+
13
+ class << self
14
+ def split(query)
15
+ query.split(TERM_SEP)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ require 'saringan/operator'
2
+
3
+ module Saringan
4
+ class Translator
5
+ class << self
6
+ def translate(query)
7
+ terms = term.split(query)
8
+ parsed = terms.map do |term|
9
+ operator.parse(term)
10
+ end
11
+ (parsed.size > 1) ? parsed : parsed.first
12
+ end
13
+
14
+ private
15
+
16
+ def term
17
+ Saringan::Term
18
+ end
19
+
20
+ def operator
21
+ Saringan::Operator
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Saringan
2
+ VERSION = "0.3.1"
3
+ end
data/lib/saringan.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "date"
2
+
3
+ require "saringan/version"
4
+
5
+ require "saringan/term"
6
+ require "saringan/translator"
@@ -0,0 +1,63 @@
1
+ require 'support/spec_helper'
2
+
3
+ describe Saringan::Operators::Equal do
4
+ describe '#match?' do
5
+ it 'should match equals operator' do
6
+ term = 'name::john'
7
+ expect(Saringan::Operators::Equal.match?(term)).to be_truthy
8
+ end
9
+
10
+ it 'should not match other operators' do
11
+ term = 'name:!:john'
12
+ expect(Saringan::Operators::Equal.match?(term)).to be_falsy
13
+ end
14
+ end
15
+
16
+ describe '#split' do
17
+ let(:term) { 'name::john' }
18
+
19
+ it 'should split term' do
20
+ splitted = Saringan::Operators::Equal.split(term)
21
+ expect(splitted.size).to eq(2)
22
+ end
23
+
24
+ context 'splitted key' do
25
+ it 'should match term key' do
26
+ splitted = Saringan::Operators::Equal.split(term)
27
+ expect(splitted[:key]).to eq('name')
28
+ end
29
+ end
30
+
31
+ context 'splitted value' do
32
+ it 'should match term value' do
33
+ splitted = Saringan::Operators::Equal.split(term)
34
+ expect(splitted[:value]).to eq('john')
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#to_h' do
40
+ it 'should transform term into hash' do
41
+ term = 'name::john'
42
+ parsed = Saringan::Operators::Equal.to_h(term)
43
+
44
+ expect(parsed).to eq({name: 'john'})
45
+ end
46
+ end
47
+
48
+ describe '#to_query' do
49
+ it 'should transform term keys into query' do
50
+ term = 'name::john'
51
+ parsed = Saringan::Operators::Equal.to_query(term)
52
+
53
+ expect(parsed[:query]).to eq("name = ?")
54
+ end
55
+
56
+ it 'should transform term values into params to query' do
57
+ term = 'name::john'
58
+ parsed = Saringan::Operators::Equal.to_query(term)
59
+
60
+ expect(parsed[:params]).to eq('john')
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ require 'support/spec_helper'
3
+
4
+ describe Saringan::Parsers::DateTimeRange do
5
+ let(:parser) { Saringan::Parsers::DateTimeRange }
6
+ let(:from ) { DateTime.new(2018, 06, 01, 00, 00, 00, DateTime.current.zone) }
7
+ let(:to) { DateTime.new(2018, 06, 30, 23, 59, 59, DateTime.current.zone) }
8
+
9
+ describe '#match?' do
10
+ it 'should match date time range value' do
11
+ value = 'dt[2018-06-01 00:00:00|2018-06-30 23:59:59]'
12
+ expect(parser.match?(value)).to be_truthy
13
+ end
14
+
15
+ it 'should not match non date time range value' do
16
+ value = 'i[1|5]'
17
+ expect(parser.match?(value)).to be_falsy
18
+ end
19
+ end
20
+
21
+ describe '#clean' do
22
+ it 'should remove range markup from value' do
23
+ value = 'dt[2018-06-01 00:00:00|2018-06-30 23:59:59]'
24
+ expect(parser.clean(value)).to eq('2018-06-01 00:00:00|2018-06-30 23:59:59')
25
+ end
26
+ end
27
+
28
+ describe '#split' do
29
+ it 'should split value into from/to array' do
30
+ value = 'dt[2018-06-01 00:00:00|2018-06-30 23:59:59]'
31
+ expect(parser.split(value)).to eq([from, to])
32
+ end
33
+ end
34
+
35
+ describe '#to_h' do
36
+ it 'should translate value into from/to hash' do
37
+ value = 'dt[2018-06-01 00:00:00|2018-06-30 23:59:59]'
38
+ expect(parser.to_h(value)).to eq({from: from, to: to })
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ # require 'support/spec_helper'
2
+ #
3
+ # describe Saringan::Parsers::IntegerRange do
4
+ # let(:parser){ Saringan::Parsers::IntegerRange }
5
+ #
6
+ # describe '#match?' do
7
+ # it 'should match range value' do
8
+ # value = 'i[1|3]'
9
+ # expect(parser.match?(value)).to be_truthy
10
+ # end
11
+ #
12
+ # it 'should not match non integer range value' do
13
+ # value = '[1|3]'
14
+ # expect(parser.match?(value)).to be_falsy
15
+ # end
16
+ # end
17
+ # end
@@ -0,0 +1,31 @@
1
+ require 'support/spec_helper'
2
+
3
+ describe Saringan::Parsers::Range do
4
+ let(:parser){ Saringan::Parsers::Range }
5
+
6
+ describe '#match?' do
7
+ it 'should match range value' do
8
+ value = '[1|10]'
9
+ expect(parser.match?(value)).to be_truthy
10
+ end
11
+
12
+ it 'should not match non range value' do
13
+ value = '[1|10'
14
+ expect(parser.match?(value)).to be_falsy
15
+ end
16
+ end
17
+
18
+ describe '#clean' do
19
+ it 'should remove range markup from value' do
20
+ value = '[1|3]'
21
+ expect(parser.clean(value)).to eq('1|3')
22
+ end
23
+ end
24
+
25
+ describe '#splt' do
26
+ it 'should separate range in from/to array' do
27
+ value = '[1|3]'
28
+ expect(parser.split(value)).to eq(["1", "3"])
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ RSpec.describe Saringan do
2
+ it "has a version number" do
3
+ expect(Saringan::VERSION).not_to be nil
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ require "saringan"
2
+
3
+ RSpec.configure do |config|
4
+ config.run_all_when_everything_filtered = true
5
+ config.order = 'random'
6
+ end
@@ -0,0 +1,16 @@
1
+ require 'support/spec_helper'
2
+
3
+ describe Saringan::Term do
4
+ let(:query) { 'name:name,age:18,gender:male' }
5
+
6
+ it 'should separate query terms' do
7
+ terms = Saringan::Term.split(query)
8
+ expect(terms.size).to eq(3)
9
+ end
10
+
11
+ it 'should match query terms' do
12
+ splited = %w(name:name age:18 gender:male)
13
+ terms = Saringan::Term.split(query)
14
+ expect(terms).to eq(splited)
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ require 'support/spec_helper'
2
+
3
+ describe Saringan::Translator do
4
+ let(:translator) { Saringan::Translator }
5
+
6
+ describe '#translate' do
7
+ context 'for date time ranges' do
8
+ let(:query) { 'created_at::dt[2018-06-01 00:00:00|2018-06-30 23:59:59]' }
9
+
10
+ it 'should translate date time query string to ruby hash' do
11
+ from = DateTime.new(2018, 06, 01, 00, 00, 00, DateTime.current.zone)
12
+ to = DateTime.new(2018, 06, 30, 23, 59, 59, DateTime.current.zone)
13
+
14
+ expect(translator.translate(query)).to eq({ created_at: from..to })
15
+ end
16
+ end
17
+
18
+ context 'for absolute equal values' do
19
+ context 'and value is string' do
20
+ let(:query) { 'name::john' }
21
+
22
+ it 'translate query string to ruby hash' do
23
+ expect(translator.translate(query)).to eq({ name: 'john' })
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: saringan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ platform: ruby
6
+ authors:
7
+ - Reinaldo Olivera (k1ng)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-07-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '12.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '12.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-meta
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.0'
69
+ description: Simple way to send filter parameters to rails models.
70
+ email:
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - MIT-LICENSE
76
+ - README.md
77
+ - lib/saringan.rb
78
+ - lib/saringan/operator.rb
79
+ - lib/saringan/operators.rb
80
+ - lib/saringan/operators/equal.rb
81
+ - lib/saringan/parser.rb
82
+ - lib/saringan/parsers.rb
83
+ - lib/saringan/parsers/date_time_range.rb
84
+ - lib/saringan/parsers/integer_range.rb
85
+ - lib/saringan/parsers/range.rb
86
+ - lib/saringan/term.rb
87
+ - lib/saringan/translator.rb
88
+ - lib/saringan/version.rb
89
+ - spec/operators/equal_spec.rb
90
+ - spec/parsers/date_time_range_spec.rb
91
+ - spec/parsers/integer_range_spec.rb
92
+ - spec/parsers/range_spec.rb
93
+ - spec/saringan_spec.rb
94
+ - spec/support/spec_helper.rb
95
+ - spec/terms_spec.rb
96
+ - spec/translator_spec.rb
97
+ homepage: https://github.com/reinaldooli/saringan
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.7.6
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Simple way to send filter parameters to rails models.
121
+ test_files:
122
+ - spec/operators/equal_spec.rb
123
+ - spec/terms_spec.rb
124
+ - spec/support/spec_helper.rb
125
+ - spec/translator_spec.rb
126
+ - spec/parsers/date_time_range_spec.rb
127
+ - spec/parsers/integer_range_spec.rb
128
+ - spec/parsers/range_spec.rb
129
+ - spec/saringan_spec.rb