saringan 0.4.1 → 0.5.0

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/saringan/operator.rb +12 -14
  3. data/lib/saringan/operators/equal.rb +7 -24
  4. data/lib/saringan/operators/greater.rb +24 -0
  5. data/lib/saringan/operators/greater_equal.rb +24 -0
  6. data/lib/saringan/parser.rb +12 -13
  7. data/lib/saringan/parsers/date.rb +28 -0
  8. data/lib/saringan/parsers/date_time.rb +13 -16
  9. data/lib/saringan/parsers/string.rb +14 -0
  10. data/lib/saringan/qualifier.rb +28 -2
  11. data/lib/saringan/qualifiers/absolute.rb +23 -0
  12. data/lib/saringan/qualifiers/between.rb +19 -9
  13. data/lib/saringan/qualifiers/inclusion.rb +20 -9
  14. data/lib/saringan/qualifiers/range.rb +2 -19
  15. data/lib/saringan/statement.rb +17 -0
  16. data/lib/saringan/statements/abstract_statement.rb +18 -0
  17. data/lib/saringan/statements/equal.rb +11 -0
  18. data/lib/saringan/statements/greater_equal.rb +20 -0
  19. data/lib/saringan/term.rb +0 -5
  20. data/lib/saringan/translator.rb +4 -3
  21. data/lib/saringan/version.rb +1 -1
  22. data/spec/operators/equal_spec.rb +8 -42
  23. data/spec/operators/greater_equal_spec.rb +32 -0
  24. data/spec/operators/greater_spec.rb +32 -0
  25. data/spec/parsers/date_spec.rb +45 -0
  26. data/spec/parsers/date_time_spec.rb +2 -11
  27. data/spec/qualifiers/between_spec.rb +19 -3
  28. data/spec/qualifiers/inclusion_spec.rb +19 -4
  29. data/spec/qualifiers/range_spec.rb +4 -15
  30. data/spec/translations/absolute/date/equal_spec.rb +0 -0
  31. data/spec/translations/absolute/date/greater_equal_spec.rb +19 -0
  32. data/spec/translations/absolute/date/greater_spec.rb +0 -0
  33. data/spec/translations/absolute/string/equal_spec.rb +30 -0
  34. data/spec/translations/range/date_time_spec.rb +25 -0
  35. data/spec/translator_spec.rb +42 -17
  36. metadata +28 -7
  37. data/lib/saringan/operators/range.rb +0 -55
  38. data/lib/saringan/parsers/integer_range.rb +0 -10
  39. data/spec/operators/range_spec.rb +0 -83
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 791993cb596de66e181c0b65604c7a8c8966806174e7ce974f4d30b76a0d9afd
4
- data.tar.gz: cdc0e6d8e7fce69c3f43f8aa3e42ee4193ed1305aadecccf4cad57d74922691b
3
+ metadata.gz: d91fddd56fb7a75587ea167883cc517de89c4865c03effe5da0cc59337499ccb
4
+ data.tar.gz: fcbe331554be9d86cc74efcc743c46ab8172fde974804907851544bed702687e
5
5
  SHA512:
6
- metadata.gz: eb697205169202b661ede5b47cc681cf069f59d34e9069a0618035485f8842723e679e577879948085767145e4b13659469530db410370a4e9f5b7c64d7a6626
7
- data.tar.gz: 6cdf0fdaae73799c625104b27f6062e1c4fb287fcaea484592c7fd559baf0aa113e0f245b8cb9ebfd9e78c39bdbefd6e21bf0c9aa23e3b962cc6751f7523d445
6
+ metadata.gz: f798d7b85db4b9cfaafe4a3967a7d69b1ab1f22722e2bfabe88fbea0e55ab498f9c63fd44d20c8f03e36452a5751f6ba06e2c82918ef8ff0697407fbf00d068c
7
+ data.tar.gz: a49cfa55062c6944cbc02e25edf5c5a230c86f1097e1eacbe1c3f7e94d5c5210e444b8ec429ea6cf5f82fe2972369941c62114609810996e0a98b141754d414b
@@ -1,26 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
  # -*- encoding: utf-8 -*-
3
3
 
4
- require "saringan/operators/equal"
5
- require "saringan/operators/range"
4
+ require 'saringan/operators/equal'
5
+ require 'saringan/operators/greater'
6
+ require 'saringan/operators/greater_equal'
6
7
 
7
8
  module Saringan
8
9
  class Operator
9
- class << self
10
- def parse(term)
11
- return equal.to_h(term) if equal.match?(term)
12
- return range.to_h(term) if range.match?(term)
13
- end
14
-
15
- private
16
10
 
17
- def equal
18
- Saringan::Operators::Equal
19
- end
11
+ OPERATORS = [
12
+ Saringan::Operators::Equal,
13
+ Saringan::Operators::GreaterEqual
14
+ ]
20
15
 
21
- def range
22
- Saringan::Operators::Range
16
+ class << self
17
+ def build(term)
18
+ OPERATORS.each do |operator|
19
+ return operator.new(term) if operator.match?(term)
23
20
  end
21
+ end
24
22
  end
25
23
  end
26
24
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  # -*- encoding: utf-8 -*-
3
3
 
4
- require 'saringan/parser'
5
4
  require 'saringan/matcher'
5
+ require 'saringan/statements/equal'
6
6
 
7
7
  module Saringan
8
8
  module Operators
@@ -11,34 +11,17 @@ module Saringan
11
11
 
12
12
  OP_EQUAL = /::/
13
13
 
14
- class << self
14
+ attr_reader :subject, :value
15
15
 
16
- # TODO: Create an absolute qualifier
17
- def to_h(term)
18
- splitted = split(term)
19
- { "#{splitted[:key]}": parser.parse(splitted[:value]) }
20
- end
21
-
22
- def to_query(term)
23
- splitted = split(term)
24
- { query: "#{splitted[:key]} = ?", params: splitted[:value] }
25
- end
16
+ def initialize(term)
17
+ @subject, @value = term.split(OP_EQUAL, 2)
18
+ end
26
19
 
27
- def split(term)
28
- splitted = term.split(OP_EQUAL)
29
- { key: splitted[0], value: splitted[1] }
30
- end
20
+ private
31
21
 
32
- def matcher
22
+ def self.matcher
33
23
  OP_EQUAL
34
24
  end
35
-
36
- private
37
-
38
- def parser
39
- Saringan::Parser
40
- end
41
- end
42
25
  end
43
26
  end
44
27
  end
@@ -0,0 +1,24 @@
1
+ require 'saringan/matcher'
2
+ require 'saringan/parser'
3
+
4
+ module Saringan
5
+ module Operators
6
+ class Greater
7
+ extend Saringan::Matcher
8
+
9
+ OP_GREATER = /:>/
10
+
11
+ attr_reader :subject, :value
12
+
13
+ def initialize(term)
14
+ @subject, @value = term.split(OP_GREATER)
15
+ end
16
+
17
+ private
18
+
19
+ def self.matcher
20
+ OP_GREATER
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'saringan/matcher'
2
+ # require 'saringan/parser'
3
+
4
+ module Saringan
5
+ module Operators
6
+ class GreaterEqual
7
+ extend Saringan::Matcher
8
+
9
+ OP_GREATER_EQUAL = />:/
10
+
11
+ attr_reader :subject, :value
12
+
13
+ def initialize(term)
14
+ @subject, @value = term.split(OP_GREATER_EQUAL)
15
+ end
16
+
17
+ private
18
+
19
+ def self.matcher
20
+ OP_GREATER_EQUAL
21
+ end
22
+ end
23
+ end
24
+ end
@@ -2,25 +2,24 @@
2
2
  # -*- encoding: utf-8 -*-
3
3
 
4
4
  require 'saringan/parsers/date_time'
5
+ require 'saringan/parsers/date'
6
+ require 'saringan/parsers/string'
5
7
 
6
8
  module Saringan
7
9
  class Parser
8
- class << self
9
- def parse(value)
10
- return date_time.parse(value) if date_time.match?(value)
11
- value
12
- end
13
-
14
- def build(value)
15
- return {value: date_time.clean(value), parser: date_time} if date_time.match?(value)
16
- { value: value, parser: nil }
17
- end
18
10
 
19
- private
11
+ PARSERS = [
12
+ Saringan::Parsers::DateTime,
13
+ Saringan::Parsers::Date
14
+ ]
20
15
 
21
- def date_time
22
- Saringan::Parsers::DateTime
16
+ class << self
17
+ def build(value)
18
+ PARSERS.each do |parser|
19
+ return parser if parser.match?(value)
23
20
  end
21
+ Saringan::Parsers::String
22
+ end
24
23
  end
25
24
  end
26
25
  end
@@ -0,0 +1,28 @@
1
+ require 'saringan/matcher'
2
+
3
+ module Saringan
4
+ module Parsers
5
+ class Date
6
+ extend Saringan::Matcher
7
+
8
+ MATCHER = /^d\((.+)\)$/
9
+ FORMAT = '%Y-%m-%d'
10
+
11
+ class << self
12
+ def clean(value)
13
+ value.gsub(/^d\(|\)$/, '')
14
+ end
15
+
16
+ def parse(value)
17
+ cleaned = clean(value)
18
+ ::Date.strptime(cleaned, FORMAT)
19
+ end
20
+ alias_method :to_proc, :parse
21
+
22
+ def matcher
23
+ MATCHER
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  # -*- encoding: utf-8 -*-
3
-
4
3
  require 'active_support/core_ext/time'
5
4
  require 'active_support/core_ext/date_time'
6
5
  require 'saringan/matcher'
@@ -10,26 +9,24 @@ module Saringan
10
9
  class DateTime
11
10
  extend Saringan::Matcher
12
11
 
13
- MATCHER = /^dt\[(.+)\]$/
14
- FORMAT = '%Y-%m-%d %H:%M:%S'
12
+ MATCHER = /^dt(\(|\[)(.+)(\)|\])$/
13
+ FORMAT = '%Y-%m-%dT%H:%M:%S'
15
14
 
16
- class << self
17
- def clean(value)
18
- value.gsub(/^dt\[|\]$/, '')
19
- end
15
+ def self.parse(value)
16
+ date = ::DateTime.strptime(value, FORMAT)
17
+ ::DateTime.new date.year, date.month, date.day, date.hour, date.min, \
18
+ date.sec, ::DateTime.current.zone
19
+ end
20
20
 
21
- def parse(value)
22
- cleaned = clean(value)
23
- date = ::DateTime.strptime(cleaned, FORMAT)
24
- ::DateTime.new date.year, date.month, date.day, date.hour, date.min, \
25
- date.sec, ::DateTime.current.zone
26
- end
27
- alias_method :to_proc, :parse
21
+ def self.clean(value)
22
+ value.gsub(/^dt/, '')
23
+ end
24
+
25
+ private
28
26
 
29
- def matcher
27
+ def self.matcher
30
28
  MATCHER
31
29
  end
32
- end
33
30
  end
34
31
  end
35
32
  end
@@ -0,0 +1,14 @@
1
+ module Saringan
2
+ module Parsers
3
+ class String
4
+
5
+ def self.parse(value)
6
+ value.to_s
7
+ end
8
+
9
+ def self.clean(value)
10
+ parse value
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,14 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
  # -*- encoding: utf-8 -*-
3
3
 
4
+ require 'saringan/qualifiers/absolute'
5
+ require 'saringan/qualifiers/between'
6
+ require 'saringan/qualifiers/inclusion'
4
7
  require 'saringan/qualifiers/range'
5
8
 
6
9
  module Saringan
7
10
  class Qualifier
8
11
 
12
+ RANGE_QUALIFIERS = [
13
+ Saringan::Qualifiers::Between
14
+ ]
15
+
9
16
  class << self
10
- def qualify(value)
11
- range.parse_value(value) if range.match?(value)
17
+ def build(value)
18
+ parser = Saringan::Parser.build(value)
19
+ value = parser.clean(value)
20
+ qualifier = nil
21
+
22
+ if range.match?(value)
23
+ value = range.clean(value)
24
+ RANGE_QUALIFIERS.each do |q|
25
+ qualifier = q if q.match?(value)
26
+ end
27
+ qualifier ||= Saringan::Qualifiers::Inclusion
28
+ else
29
+ value = absolute.clean(value)
30
+ qualifier = absolute
31
+ end
32
+
33
+ qualifier.new(value, parser)
12
34
  end
13
35
 
14
36
  private
@@ -17,6 +39,10 @@ module Saringan
17
39
  Saringan::Qualifiers::Range
18
40
  end
19
41
 
42
+ def absolute
43
+ Saringan::Qualifiers::Absolute
44
+ end
45
+
20
46
  end
21
47
  end
22
48
  end
@@ -0,0 +1,23 @@
1
+ module Saringan
2
+ module Qualifiers
3
+ class Absolute
4
+
5
+ QL_REPLACER = /^\(|\)$/
6
+ TYPE = :absolute
7
+
8
+ def initialize(value, parser)
9
+ @value = self.class.clean(value)
10
+ @parser = parser
11
+ end
12
+
13
+ def value
14
+ @parser.parse(@value)
15
+ end
16
+
17
+ def self.clean(value)
18
+ value.gsub(QL_REPLACER, '')
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -8,18 +8,28 @@ module Saringan
8
8
  class Between
9
9
  extend Saringan::Matcher
10
10
 
11
- QL_BETWEEN = /\~+/
11
+ MATCHER = /\~+/
12
+ TYPE = :between
12
13
 
13
- class << self
14
- def matcher
15
- QL_BETWEEN
16
- end
14
+ def initialize(value, parser)
15
+ @value = value
16
+ @parser = parser
17
+ qualify
18
+ end
17
19
 
18
- def qualify(value, parser = nil)
19
- splitted = value.split(QL_BETWEEN)[0,2]
20
- splitted.map{|v| parser.nil? ? v : parser.parse(v)}
21
- end
20
+ def qualify
21
+ @from, @to = @value.split(MATCHER, 2)
22
+ end
23
+
24
+ def value
25
+ @parser.parse(@from)..@parser.parse(@to)
22
26
  end
27
+
28
+ private
29
+
30
+ def self.matcher
31
+ MATCHER
32
+ end
23
33
  end
24
34
  end
25
35
  end
@@ -8,18 +8,29 @@ module Saringan
8
8
  class Inclusion
9
9
  extend Saringan::Matcher
10
10
 
11
- QL_INCLUSION = /\;+/
11
+ MATCHER = /\|+/
12
+ TYPE = :inclusion
12
13
 
13
- class << self
14
- def qualify(value, parser = nil)
15
- splitted = value.split(QL_INCLUSION)
16
- parser.nil? ? splitted : splitted.map(&parser)
17
- end
14
+ def initialize(value, parser)
15
+ @value = value
16
+ @parser = parser
17
+ qualify
18
+ end
18
19
 
19
- def matcher
20
- QL_INCLUSION
21
- end
20
+ def qualify
21
+ @values = @value.split(MATCHER).map(&:strip)
22
+ end
23
+
24
+ def value
25
+ @values.map{|val| @parser.parse(val)}
22
26
  end
27
+
28
+ private
29
+
30
+ def self.matcher
31
+ MATCHER
32
+ end
33
+
23
34
  end
24
35
  end
25
36
  end
@@ -1,6 +1,4 @@
1
1
  require 'saringan/matcher'
2
- require 'saringan/qualifiers/inclusion'
3
- require 'saringan/qualifiers/between'
4
2
 
5
3
  module Saringan
6
4
  module Qualifiers
@@ -15,25 +13,10 @@ module Saringan
15
13
  QL_RANGE
16
14
  end
17
15
 
18
- def qualify(value, parser)
19
- cleaned = value.gsub(QL_REPLACER, '')
20
-
21
- if between.match?(value)
22
- { type: :between, value: between.qualify(cleaned, parser) }
23
- else
24
- { type: :in, value: inclusion.qualify(cleaned, parser) }
25
- end
16
+ def clean(value)
17
+ value.gsub(QL_REPLACER, '')
26
18
  end
27
19
 
28
- private
29
-
30
- def inclusion
31
- Saringan::Qualifiers::Inclusion
32
- end
33
-
34
- def between
35
- Saringan::Qualifiers::Between
36
- end
37
20
  end
38
21
  end
39
22
  end
@@ -0,0 +1,17 @@
1
+ require 'saringan/statements/equal'
2
+ require 'saringan/statements/greater_equal'
3
+
4
+ module Saringan
5
+ class Statement
6
+ def self.build(term)
7
+ operator = Saringan::Operator.build(term)
8
+
9
+ case operator
10
+ when Operators::Equal
11
+ Statements::Equal.new(operator)
12
+ when Operators::GreaterEqual
13
+ Statements::GreaterEqual.new(operator)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ require 'saringan/qualifier'
2
+
3
+ module Saringan
4
+ module Statements
5
+ class AbstractStatement
6
+ attr_reader :operator, :qualifier, :field, :value, :type,
7
+ :subject, :params
8
+
9
+ def initialize(operator)
10
+ @operator = operator
11
+ @qualifier = Saringan::Qualifier.build(@operator.value)
12
+ @field = @operator.subject
13
+ @value = @qualifier.value
14
+ @type = @qualifier.class::TYPE
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ require 'saringan/statements/abstract_statement'
2
+
3
+ module Saringan
4
+ module Statements
5
+ class Equal < AbstractStatement
6
+ def to_query
7
+ {"#{@operator.subject}": @qualifier.value}
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ require 'active_support/concern'
2
+ require 'saringan/statements/abstract_statement'
3
+
4
+ module Saringan
5
+ module Statements
6
+ class GreaterEqual < AbstractStatement
7
+ def to_query
8
+ [subject, params]
9
+ end
10
+
11
+ def subject
12
+ "#{@operator.subject} >= ?"
13
+ end
14
+
15
+ def params
16
+ @qualifier.value
17
+ end
18
+ end
19
+ end
20
+ end
@@ -5,11 +5,6 @@ module Saringan
5
5
  class Term
6
6
  TERM_SEP = ','
7
7
 
8
- OP_N_EQUAL_S = /:!:/
9
- OP_N_EQUAL_I = /:<>:/
10
- OP_LESS = /:<:/
11
- OP_BIGGER = /:>:/
12
-
13
8
  class << self
14
9
  def split(query)
15
10
  query.split(TERM_SEP)
@@ -2,15 +2,16 @@
2
2
  # -*- encoding: utf-8 -*-
3
3
 
4
4
  require 'saringan/operator'
5
+ require 'saringan/statement'
5
6
 
6
7
  module Saringan
7
8
  class Translator
8
9
  class << self
9
10
  def translate(query)
10
11
  terms = term.split(query)
11
- parsed = {}
12
- terms.each{|term| parsed.merge!(operator.parse(term))}
13
- parsed
12
+ terms.map do |t|
13
+ Saringan::Statement.build(t).to_query
14
+ end
14
15
  end
15
16
 
16
17
  private
@@ -1,3 +1,3 @@
1
1
  module Saringan
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -4,6 +4,8 @@
4
4
  require 'support/spec_helper'
5
5
 
6
6
  describe Saringan::Operators::Equal do
7
+ let(:operator) { described_class }
8
+
7
9
  describe '#match?' do
8
10
  it 'should match equals operator' do
9
11
  term = 'name::john'
@@ -16,51 +18,15 @@ describe Saringan::Operators::Equal do
16
18
  end
17
19
  end
18
20
 
19
- describe '#split' do
20
- let(:term) { 'name::john' }
21
-
22
- it 'should split term' do
23
- splitted = Saringan::Operators::Equal.split(term)
24
- expect(splitted.size).to eq(2)
25
- end
26
-
27
- context 'splitted key' do
28
- it 'should match term key' do
29
- splitted = Saringan::Operators::Equal.split(term)
30
- expect(splitted[:key]).to eq('name')
31
- end
32
- end
21
+ context 'initialization' do
22
+ let(:instance) { operator.new('name::john') }
33
23
 
34
- context 'splitted value' do
35
- it 'should match term value' do
36
- splitted = Saringan::Operators::Equal.split(term)
37
- expect(splitted[:value]).to eq('john')
38
- end
24
+ it 'extract term subject' do
25
+ expect(instance.subject).to eq('name')
39
26
  end
40
- end
41
-
42
- describe '#to_h' do
43
- it 'should transform term into hash' do
44
- term = 'name::john'
45
- parsed = Saringan::Operators::Equal.to_h(term)
46
-
47
- expect(parsed).to eq({name: 'john'})
48
- end
49
- end
50
-
51
- describe '#to_query' do
52
- it 'should transform term keys into query' do
53
- term = 'name::john'
54
- parsed = Saringan::Operators::Equal.to_query(term)
55
-
56
- expect(parsed[:query]).to eq("name = ?")
57
- end
58
-
59
- it 'should transform term values into params to query' do
60
- term = 'name::john'
61
- parsed = Saringan::Operators::Equal.to_query(term)
62
27
 
63
- expect(parsed[:params]).to eq('john')
28
+ it 'extract term value' do
29
+ expect(instance.value).to eq('john')
64
30
  end
65
31
  end
66
32
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'support/spec_helper'
5
+
6
+ describe Saringan::Operators::GreaterEqual do
7
+ let(:operator) { described_class }
8
+
9
+ describe '#match?' do
10
+ it 'should match greater operator' do
11
+ term = 'name>:john'
12
+ expect(operator.match?(term)).to be_truthy
13
+ end
14
+
15
+ it 'should not match other operators' do
16
+ term = 'name!:john'
17
+ expect(operator.match?(term)).to be_falsy
18
+ end
19
+ end
20
+
21
+ context 'initialization' do
22
+ let(:instance) { operator.new('name>:john') }
23
+
24
+ it 'extract term subject' do
25
+ expect(instance.subject).to eq('name')
26
+ end
27
+
28
+ it 'extract term value' do
29
+ expect(instance.value).to eq('john')
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'support/spec_helper'
5
+
6
+ describe Saringan::Operators::Greater do
7
+ let(:operator) { described_class }
8
+
9
+ describe '#match?' do
10
+ it 'should match greater operator' do
11
+ term = 'name:>john'
12
+ expect(operator.match?(term)).to be_truthy
13
+ end
14
+
15
+ it 'should not match other operators' do
16
+ term = 'name:!:john'
17
+ expect(operator.match?(term)).to be_falsy
18
+ end
19
+ end
20
+
21
+ context 'initialization' do
22
+ let(:instance) { operator.new('name:>john') }
23
+
24
+ it 'extract term subject' do
25
+ expect(instance.subject).to eq('name')
26
+ end
27
+
28
+ it 'extract term value' do
29
+ expect(instance.value).to eq('john')
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'support/spec_helper'
5
+
6
+ describe Saringan::Parsers::Date, type: :parsers do
7
+ let(:parser) { described_class }
8
+ let(:date) { Date.new(2018, 06, 01) }
9
+
10
+ describe '#match?' do
11
+ it 'match date value' do
12
+ value = 'd(2018-06-01)'
13
+ expect(parser.match?(value)).to be_truthy
14
+ end
15
+
16
+ it 'match date time value' do
17
+ value = 'd(2018-06-01T00:00:00.000)'
18
+ expect(parser.match?(value)).to be_truthy
19
+ end
20
+
21
+ it 'do not match non date value' do
22
+ value = 'i(1)'
23
+ expect(parser.match?(value)).to be_falsy
24
+ end
25
+ end
26
+
27
+ describe '#clean' do
28
+ it 'remove range markup from value' do
29
+ value = 'd(2018-06-01)'
30
+ expect(parser.clean(value)).to eq('2018-06-01')
31
+ end
32
+ end
33
+
34
+ describe '#parse' do
35
+ it 'parse value to Date' do
36
+ value = 'd(2018-06-01)'
37
+ expect(parser.parse(value)).to eq(date)
38
+ end
39
+
40
+ it 'parse value to Date even value is a DateTime' do
41
+ value = 'd(2018-06-01T00:00:00.000)'
42
+ expect(parser.parse(value)).to eq(date)
43
+ end
44
+ end
45
+ end
@@ -23,23 +23,14 @@ describe Saringan::Parsers::DateTime, type: :parsers do
23
23
  describe '#clean' do
24
24
  it 'should remove range markup from value' do
25
25
  value = 'dt[2018-06-01 00:00:00|2018-06-30 23:59:59]'
26
- expect(parser.clean(value)).to eq('2018-06-01 00:00:00|2018-06-30 23:59:59')
26
+ expect(parser.clean(value)).to eq('[2018-06-01 00:00:00|2018-06-30 23:59:59]')
27
27
  end
28
28
  end
29
29
 
30
30
  describe '#parse' do
31
31
  it 'should parse value to DateTime' do
32
- value = '2018-06-01 00:00:00'
32
+ value = '2018-06-01T00:00:00'
33
33
  expect(parser.parse(value)).to eq(from)
34
34
  end
35
35
  end
36
-
37
- # describe '#to_h' do
38
- # context 'using between translator' do
39
- # it 'should translate value into from/to hash' do
40
- # value = 'dt[2018-06-01 00:00:00|2018-06-30 23:59:59]'
41
- # expect(parser.to_h(value)[:value]).to eq([from, to])
42
- # end
43
- # end
44
- # end
45
36
  end
@@ -19,9 +19,25 @@ describe Saringan::Qualifiers::Between, type: :qualifier do
19
19
  end
20
20
 
21
21
  describe '#qualify' do
22
- it 'parse value to array' do
23
- value = 'val~val~val'
24
- expect(qualifier.qualify(value)).to have(2).items
22
+ let(:parser) { double('parser') }
23
+
24
+ before do
25
+ allow(parser).to receive(:parser).and_return(1, 10)
26
+ end
27
+
28
+ it 'split values in two parts' do
29
+ value = '1~1~10'
30
+ instance = qualifier.new(value, parser)
31
+
32
+ expect(instance.qualify).to have(2).items
25
33
  end
34
+
35
+ it 'split values correctly' do
36
+ value = '1~10'
37
+ instance = qualifier.new(value, parser)
38
+
39
+ expect(instance.qualify).to eq(['1', '10'])
40
+ end
41
+
26
42
  end
27
43
  end
@@ -8,7 +8,7 @@ describe Saringan::Qualifiers::Inclusion, type: :qualifier do
8
8
 
9
9
  describe '#match?' do
10
10
  it 'matches inclusion value' do
11
- value = 'val; val; val'
11
+ value = 'val| val| val'
12
12
  expect(qualifier.match?(value)).to be_truthy
13
13
  end
14
14
 
@@ -19,9 +19,24 @@ describe Saringan::Qualifiers::Inclusion, type: :qualifier do
19
19
  end
20
20
 
21
21
  describe '#qualify' do
22
- it 'parse value to array' do
23
- value = 'val;val;val'
24
- expect(qualifier.qualify(value)).to have(3).items
22
+ let(:parser) { double('parser') }
23
+
24
+ before do
25
+ allow(parser).to receive(:parse).and_return('val')
26
+ end
27
+
28
+ it 'parsed value match value size' do
29
+ value = 'val|val|val'
30
+ instance = qualifier.new(value, parser)
31
+
32
+ expect(instance.qualify).to have(3).items
33
+ end
34
+
35
+ it 'parsed value must match value' do
36
+ value = 'val|val|val'
37
+ instance = qualifier.new(value, parser)
38
+
39
+ expect(instance.qualify).to eq(['val', 'val', 'val'])
25
40
  end
26
41
  end
27
42
  end
@@ -28,21 +28,10 @@ describe Saringan::Qualifiers::Range, type: :qualifier do
28
28
  end
29
29
  end
30
30
 
31
- describe '#qualify' do
32
- context 'for inclusion values' do
33
- it 'parse inclusion values as array' do
34
- value = 'val; val; val'
35
- parsed = qualifier.qualify(value, nil)
36
- expect(parsed[:value]).to have(3).items
37
- end
38
- end
39
-
40
- context 'for between values' do
41
- it 'parse between values as from/to hash' do
42
- value = 'val~val~val'
43
- parsed = qualifier.qualify(value, nil)
44
- expect(parsed[:value]).to have(2).items
45
- end
31
+ describe '#clean' do
32
+ it 'clean range value markup' do
33
+ value, expected = '[value]', 'value'
34
+ expect(qualifier.clean(value)).to eq(expected)
46
35
  end
47
36
  end
48
37
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'support/spec_helper'
5
+
6
+ describe Saringan::Translator do
7
+ let(:translator) { described_class }
8
+ let(:date) { Date.today }
9
+ let(:query) { "date>:d(#{date.iso8601})" }
10
+
11
+ describe '#translate' do
12
+ context 'greater equal date' do
13
+ it 'translates correctly' do
14
+ translated = translator.translate(query)
15
+ expect(translated[0]).to eq(["date >= ?", date])
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'support/spec_helper'
5
+
6
+ describe Saringan::Translator do
7
+ let(:translator) { described_class }
8
+
9
+ describe '#translate' do
10
+ context 'equal string' do
11
+ it 'translates correctly' do
12
+ translated = translator.translate('name::john')
13
+ expect(translated).to eq([{name: 'john'}])
14
+ end
15
+ end
16
+
17
+ context 'multiple terms' do
18
+ it 'translate terms correctly' do
19
+ translated = translator
20
+ .translate('name::john,last_name::(doe),email::j.doe@email.com')
21
+
22
+ expect(translated).to eq([
23
+ {name: 'john'},
24
+ {last_name: 'doe'},
25
+ {email: 'j.doe@email.com'}
26
+ ])
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'support/spec_helper'
5
+
6
+ describe Saringan::Translator do
7
+ let(:translator) { described_class }
8
+ let(:start) { DateTime.now }
9
+ let(:finish) { start + 30 }
10
+ let(:query) { "date::dt[#{start.iso8601}~#{finish.iso8601}]" }
11
+
12
+ describe '#translate' do
13
+ context 'inclusion range' do
14
+ end
15
+
16
+ context 'between range' do
17
+ it 'to rails query correctly' do
18
+ result = translator.translate(query)
19
+ expected = {"date": start..finish}
20
+
21
+ expect(result.first[:date]).not_to be_nil
22
+ end
23
+ end
24
+ end
25
+ end
@@ -7,33 +7,58 @@ describe Saringan::Translator do
7
7
  let(:translator) { Saringan::Translator }
8
8
 
9
9
  describe '#translate' do
10
- context 'for date time ranges' do
11
- let(:query) { 'created_at:>:dt[2018-06-01 00:00:00~2018-06-30 23:59:59]' }
12
10
 
13
- it 'should translate date time query string to ruby hash' do
14
- from = DateTime.new(2018, 06, 01, 00, 00, 00, DateTime.current.zone)
15
- to = DateTime.new(2018, 06, 30, 23, 59, 59, DateTime.current.zone)
11
+ # context 'for absolute equal values' do
12
+ # context 'and value is string' do
13
+ # let(:query) { 'name::john' }
16
14
 
17
- expect(translator.translate(query)).to eq({ created_at: from..to })
15
+ # it 'translate query string to ruby hash' do
16
+ # expect(translator.translate(query)).to eq({ name: 'john' })
17
+ # end
18
+ # end
19
+ # end
20
+
21
+ context 'multiple filters' do
22
+ context 'with two string values' do
23
+ let(:query) { 'name::john,alias::snow' }
24
+
25
+ it 'translate query string to ruby rash' do
26
+ expect(translator.translate(query)).to eq([{ name: 'john' }, { alias: 'snow' }])
27
+ end
18
28
  end
19
- end
20
29
 
21
- context 'for absolute equal values' do
22
- context 'and value is string' do
23
- let(:query) { 'name::john' }
30
+ context 'with date time range and string range' do
31
+ let(:start) { DateTime.now }
32
+ let(:finish) { start + 30 }
33
+
34
+ let(:query) do
35
+ "date::dt[#{start.iso8601}~#{finish.iso8601}],status::[accepted|refused]"
36
+ end
24
37
 
25
38
  it 'translate query string to ruby hash' do
26
- expect(translator.translate(query)).to eq({ name: 'john' })
39
+ result = translator.translate(query)
40
+ expected = { status: ['accepted', 'refused'] }
41
+
42
+ expect(result).to include(expected)
27
43
  end
28
44
  end
29
45
  end
30
46
 
31
- context 'with multiple filters' do
32
- let(:query) { 'name::john,age::18' }
47
+ # context 'greater equal' do
48
+ # context 'for date values' do
49
+ # let(:query) { 'birthdate>:d(2018-06-30)' }
33
50
 
34
- it 'translate query string to ruby rash' do
35
- expect(translator.translate(query)).to eq({ name: 'john', age: '18' })
36
- end
37
- end
51
+ # it 'translate query to ruby query' do
52
+ # translated = translator.translate(query)[:query]
53
+ # expect(translated).to eq("birthdate >= ?")
54
+ # end
55
+
56
+ # it 'translated value should be a Date object' do
57
+ # date = Date.parse('2018-06-30')
58
+ # translated = translator.translate(query)[:params]
59
+ # expect(translated).to eq(date)
60
+ # end
61
+ # end
62
+ # end
38
63
  end
39
64
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saringan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reinaldo Olivera (k1ng)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-23 00:00:00.000000000 Z
11
+ date: 2019-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -92,19 +92,28 @@ files:
92
92
  - lib/saringan/matcher.rb
93
93
  - lib/saringan/operator.rb
94
94
  - lib/saringan/operators/equal.rb
95
- - lib/saringan/operators/range.rb
95
+ - lib/saringan/operators/greater.rb
96
+ - lib/saringan/operators/greater_equal.rb
96
97
  - lib/saringan/parser.rb
98
+ - lib/saringan/parsers/date.rb
97
99
  - lib/saringan/parsers/date_time.rb
98
- - lib/saringan/parsers/integer_range.rb
100
+ - lib/saringan/parsers/string.rb
99
101
  - lib/saringan/qualifier.rb
102
+ - lib/saringan/qualifiers/absolute.rb
100
103
  - lib/saringan/qualifiers/between.rb
101
104
  - lib/saringan/qualifiers/inclusion.rb
102
105
  - lib/saringan/qualifiers/range.rb
106
+ - lib/saringan/statement.rb
107
+ - lib/saringan/statements/abstract_statement.rb
108
+ - lib/saringan/statements/equal.rb
109
+ - lib/saringan/statements/greater_equal.rb
103
110
  - lib/saringan/term.rb
104
111
  - lib/saringan/translator.rb
105
112
  - lib/saringan/version.rb
106
113
  - spec/operators/equal_spec.rb
107
- - spec/operators/range_spec.rb
114
+ - spec/operators/greater_equal_spec.rb
115
+ - spec/operators/greater_spec.rb
116
+ - spec/parsers/date_spec.rb
108
117
  - spec/parsers/date_time_spec.rb
109
118
  - spec/parsers/integer_range_spec.rb
110
119
  - spec/qualifiers/between_spec.rb
@@ -113,6 +122,11 @@ files:
113
122
  - spec/saringan_spec.rb
114
123
  - spec/support/spec_helper.rb
115
124
  - spec/terms_spec.rb
125
+ - spec/translations/absolute/date/equal_spec.rb
126
+ - spec/translations/absolute/date/greater_equal_spec.rb
127
+ - spec/translations/absolute/date/greater_spec.rb
128
+ - spec/translations/absolute/string/equal_spec.rb
129
+ - spec/translations/range/date_time_spec.rb
116
130
  - spec/translator_spec.rb
117
131
  homepage: https://github.com/reinaldooli/saringan
118
132
  licenses:
@@ -134,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
148
  version: '0'
135
149
  requirements: []
136
150
  rubyforge_project:
137
- rubygems_version: 2.7.6
151
+ rubygems_version: 2.7.8
138
152
  signing_key:
139
153
  specification_version: 4
140
154
  summary: Simple way to send filter parameters to rails models.
@@ -142,11 +156,18 @@ test_files:
142
156
  - spec/qualifiers/inclusion_spec.rb
143
157
  - spec/qualifiers/between_spec.rb
144
158
  - spec/qualifiers/range_spec.rb
145
- - spec/operators/range_spec.rb
159
+ - spec/operators/greater_equal_spec.rb
160
+ - spec/operators/greater_spec.rb
146
161
  - spec/operators/equal_spec.rb
147
162
  - spec/terms_spec.rb
148
163
  - spec/support/spec_helper.rb
164
+ - spec/translations/range/date_time_spec.rb
165
+ - spec/translations/absolute/date/greater_equal_spec.rb
166
+ - spec/translations/absolute/date/greater_spec.rb
167
+ - spec/translations/absolute/date/equal_spec.rb
168
+ - spec/translations/absolute/string/equal_spec.rb
149
169
  - spec/translator_spec.rb
150
170
  - spec/parsers/integer_range_spec.rb
151
171
  - spec/parsers/date_time_spec.rb
172
+ - spec/parsers/date_spec.rb
152
173
  - spec/saringan_spec.rb
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
- # -*- encoding: utf-8 -*-
3
-
4
- require 'saringan/matcher'
5
- require 'saringan/parser'
6
- require 'saringan/qualifiers/range'
7
-
8
- module Saringan
9
- module Operators
10
- class Range
11
- extend Saringan::Matcher
12
-
13
- OP_RANGE = /:>:/
14
-
15
- class << self
16
- def matcher
17
- OP_RANGE
18
- end
19
-
20
- def to_h(term)
21
- splitted = split(term)
22
- parsed = parser(splitted[:value])
23
- qualified = qualify(parsed[:value], parsed[:parser])
24
-
25
- case qualified[:type]
26
- when :in
27
- { "#{splitted[:key]}": qualified[:value] }
28
- when :between
29
- { "#{splitted[:key]}": qualified[:value][0]..qualified[:value][1] }
30
- end
31
- end
32
-
33
- def split(term)
34
- splitted = term.split(OP_RANGE)
35
- { key: splitted[0], value: splitted[1] }
36
- end
37
-
38
- def qualify(value, parser)
39
- qualifier.qualify(value, parser)
40
- end
41
-
42
- private
43
-
44
- def qualifier
45
- Saringan::Qualifiers::Range
46
- end
47
-
48
- def parser(value)
49
- Saringan::Parser.build(value)
50
- end
51
- end
52
-
53
- end
54
- end
55
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
- # -*- encoding: utf-8 -*-
3
-
4
- module Saringan
5
- module Parsers
6
- class IntegerRange < Range
7
- MATCHER = /^i\[(.+)\]$/
8
- end
9
- end
10
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
- # -*- encoding: utf-8 -*-
3
-
4
- require 'support/spec_helper'
5
-
6
- describe Saringan::Operators::Range, type: :operator do
7
- let(:operator) { described_class }
8
-
9
- describe '#qualify' do
10
- context 'for inclusion range' do
11
- it 'return values qualified as array' do
12
- value = 'val;val;val'
13
- qualified = operator.qualify(value, nil)
14
- expect(qualified[:value]).to have(3).items
15
- end
16
-
17
- it 'qualify values as inclusion' do
18
- value = 'val;val;val'
19
- qualified = operator.qualify(value, nil)
20
- expect(qualified[:type]).to eq(:in)
21
- end
22
-
23
- it 'qualified values was not changed' do
24
- value = 'val;val;val'
25
- qualified = operator.qualify(value, nil)
26
- expect(qualified[:value]).to eq(['val', 'val', 'val'])
27
- end
28
- end
29
-
30
- context 'for between range' do
31
- it 'return values qualified as array' do
32
- value = 'val~val'
33
- qualified = operator.qualify(value, nil)
34
- expect(qualified[:value]).to have(2).items
35
- end
36
-
37
- it 'qualify values as between' do
38
- value = 'val~val'
39
- qualified = operator.qualify(value, nil)
40
- expect(qualified[:type]).to eq(:between)
41
- end
42
-
43
- it 'between qualified values has only from/to values' do
44
- value = 'val1~val2~val_'
45
- qualified = operator.qualify(value, nil)
46
- expect(qualified[:value]).to eq(['val1', 'val2'])
47
- end
48
- end
49
- end
50
-
51
- describe '#split' do
52
- it 'split term as key => value hash' do
53
- term = 'status:>:[todo;doing;done]'
54
- expect(operator.split(term)).to eq({ key: 'status', value: '[todo;doing;done]'})
55
- end
56
-
57
- context 'splitted key' do
58
- it 'match term key' do
59
- term = 'status:>:[todo;doing;done]'
60
- splitted = operator.split(term)
61
- expect(splitted[:key]).to eq('status')
62
- end
63
- end
64
-
65
- context 'splitted value' do
66
- it 'match term value' do
67
- term = 'status:>:[todo;doing;done]'
68
- splitted = operator.split(term)
69
- expect(splitted[:value]).to eq('[todo;doing;done]')
70
- end
71
- end
72
- end
73
-
74
- describe '#to_h' do
75
- context 'for inclusion range' do
76
- it 'value must be an array' do
77
- term = 'status:>:[todo;doing;done]'
78
- hash = operator.to_h(term)
79
- expect(hash).to eq({ status: ['todo', 'doing', 'done'] })
80
- end
81
- end
82
- end
83
- end