agnostic_backend 0.9.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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +52 -0
- data/LICENSE.txt +21 -0
- data/README.md +345 -0
- data/Rakefile +6 -0
- data/agnostic_backend.gemspec +34 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/doc/indexable.md +292 -0
- data/doc/queryable.md +0 -0
- data/lib/agnostic_backend/cloudsearch/index.rb +99 -0
- data/lib/agnostic_backend/cloudsearch/index_field.rb +103 -0
- data/lib/agnostic_backend/cloudsearch/indexer.rb +84 -0
- data/lib/agnostic_backend/cloudsearch/remote_index_field.rb +32 -0
- data/lib/agnostic_backend/index.rb +24 -0
- data/lib/agnostic_backend/indexable/config.rb +24 -0
- data/lib/agnostic_backend/indexable/content_manager.rb +51 -0
- data/lib/agnostic_backend/indexable/field.rb +26 -0
- data/lib/agnostic_backend/indexable/field_type.rb +48 -0
- data/lib/agnostic_backend/indexable/indexable.rb +125 -0
- data/lib/agnostic_backend/indexer.rb +48 -0
- data/lib/agnostic_backend/queryable/attribute.rb +22 -0
- data/lib/agnostic_backend/queryable/cloudsearch/executor.rb +100 -0
- data/lib/agnostic_backend/queryable/cloudsearch/query.rb +29 -0
- data/lib/agnostic_backend/queryable/cloudsearch/query_builder.rb +13 -0
- data/lib/agnostic_backend/queryable/cloudsearch/result_set.rb +27 -0
- data/lib/agnostic_backend/queryable/cloudsearch/visitor.rb +127 -0
- data/lib/agnostic_backend/queryable/criteria/binary.rb +47 -0
- data/lib/agnostic_backend/queryable/criteria/criterion.rb +13 -0
- data/lib/agnostic_backend/queryable/criteria/ternary.rb +36 -0
- data/lib/agnostic_backend/queryable/criteria_builder.rb +83 -0
- data/lib/agnostic_backend/queryable/executor.rb +43 -0
- data/lib/agnostic_backend/queryable/expressions/expression.rb +65 -0
- data/lib/agnostic_backend/queryable/operations/n_ary.rb +18 -0
- data/lib/agnostic_backend/queryable/operations/operation.rb +13 -0
- data/lib/agnostic_backend/queryable/operations/unary.rb +35 -0
- data/lib/agnostic_backend/queryable/query.rb +27 -0
- data/lib/agnostic_backend/queryable/query_builder.rb +98 -0
- data/lib/agnostic_backend/queryable/result_set.rb +42 -0
- data/lib/agnostic_backend/queryable/tree_node.rb +48 -0
- data/lib/agnostic_backend/queryable/validator.rb +174 -0
- data/lib/agnostic_backend/queryable/value.rb +26 -0
- data/lib/agnostic_backend/queryable/visitor.rb +124 -0
- data/lib/agnostic_backend/rspec/matchers.rb +69 -0
- data/lib/agnostic_backend/utilities.rb +207 -0
- data/lib/agnostic_backend/version.rb +3 -0
- data/lib/agnostic_backend.rb +49 -0
- metadata +199 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
module Criteria
|
4
|
+
class Ternary < Criterion
|
5
|
+
attr_reader :attribute, :left_value, :right_value
|
6
|
+
|
7
|
+
def initialize(attribute:, left_value:, right_value:, context: nil)
|
8
|
+
@attribute, @left_value, @right_value = attribute, left_value, right_value
|
9
|
+
super([attribute, left_value, right_value], context)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Between < Ternary
|
14
|
+
def initialize(attribute:, left_value:, right_value:, context: nil)
|
15
|
+
attribute = attribute_component(attribute: attribute, context: context)
|
16
|
+
left_value = value_component(value: left_value, context: context, type: attribute.type)
|
17
|
+
right_value = value_component(value: right_value, context: context, type: attribute.type)
|
18
|
+
super(attribute: attribute, left_value: left_value, right_value: right_value, context: context)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class GreaterAndLess < Between;
|
23
|
+
end
|
24
|
+
|
25
|
+
class GreaterEqualAndLess < Between;
|
26
|
+
end
|
27
|
+
|
28
|
+
class GreaterAndLessEqual < Between;
|
29
|
+
end
|
30
|
+
|
31
|
+
class GreaterEqualAndLessEqual < Between;
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
class CriteriaBuilder
|
4
|
+
|
5
|
+
attr_reader :context
|
6
|
+
|
7
|
+
def initialize(query_builder)
|
8
|
+
@context = query_builder
|
9
|
+
end
|
10
|
+
|
11
|
+
def eq(attribute, value)
|
12
|
+
Criteria::Equal.new(attribute: attribute, value: value, context: context)
|
13
|
+
end
|
14
|
+
|
15
|
+
def neq(attribute, value)
|
16
|
+
Criteria::NotEqual.new(attribute: attribute, value: value, context: context)
|
17
|
+
end
|
18
|
+
|
19
|
+
def gt(attribute, value)
|
20
|
+
Criteria::Greater.new(attribute: attribute, value: value, context: context)
|
21
|
+
end
|
22
|
+
|
23
|
+
def lt(attribute, value)
|
24
|
+
Criteria::Less.new(attribute: attribute, value: value, context: context)
|
25
|
+
end
|
26
|
+
|
27
|
+
def ge(attribute, value)
|
28
|
+
Criteria::GreaterEqual.new(attribute: attribute, value: value, context: context)
|
29
|
+
end
|
30
|
+
|
31
|
+
def le(attribute, value)
|
32
|
+
Criteria::LessEqual.new(attribute: attribute, value: value, context: context)
|
33
|
+
end
|
34
|
+
|
35
|
+
def gt_and_lt(attribute, left_limit, right_limit)
|
36
|
+
Criteria::GreaterAndLess.new(attribute: attribute, left_value: left_limit, right_value: right_limit, context: context)
|
37
|
+
end
|
38
|
+
|
39
|
+
def gt_and_le(attribute, left_limit, right_limit)
|
40
|
+
Criteria::GreaterAndLessEqual.new(attribute: attribute, left_value: left_limit, right_value: right_limit, context: context)
|
41
|
+
end
|
42
|
+
|
43
|
+
def ge_and_lt(attribute, left_limit, right_limit)
|
44
|
+
Criteria::GreaterEqualAndLess.new(attribute: attribute, left_value: left_limit, right_value: right_limit, context: context)
|
45
|
+
end
|
46
|
+
|
47
|
+
def ge_and_le(attribute, left_limit, right_limit)
|
48
|
+
Criteria::GreaterEqualAndLessEqual.new(attribute: attribute, left_value: left_limit, right_value: right_limit, context: context)
|
49
|
+
end
|
50
|
+
|
51
|
+
def contains(attribute, value)
|
52
|
+
Criteria::Contains.new(attribute: attribute, value: value, context: context)
|
53
|
+
end
|
54
|
+
|
55
|
+
def starts(attribute, value)
|
56
|
+
Criteria::Starts.new(attribute: attribute, value: value, context: context)
|
57
|
+
end
|
58
|
+
|
59
|
+
def asc(attribute)
|
60
|
+
Operations::Ascending.new(attribute: attribute, context: context)
|
61
|
+
end
|
62
|
+
|
63
|
+
def desc(attribute)
|
64
|
+
Operations::Descending.new(attribute: attribute, context: context)
|
65
|
+
end
|
66
|
+
|
67
|
+
def not(criterion)
|
68
|
+
Operations::Not.new(operand: criterion, context: context)
|
69
|
+
end
|
70
|
+
|
71
|
+
def and(*criteria)
|
72
|
+
Operations::And.new(operands: criteria, context: context)
|
73
|
+
end
|
74
|
+
|
75
|
+
def or(*criteria)
|
76
|
+
Operations::Or.new(operands: criteria, context: context)
|
77
|
+
end
|
78
|
+
|
79
|
+
alias_method :all, :and
|
80
|
+
alias_method :any, :or
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
class Executor
|
4
|
+
|
5
|
+
attr_reader :query
|
6
|
+
attr_reader :visitor
|
7
|
+
|
8
|
+
def initialize(query, visitor)
|
9
|
+
@query, @visitor = query, visitor
|
10
|
+
end
|
11
|
+
|
12
|
+
def execute
|
13
|
+
raise NotImplementedError, 'Abstract method'
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def order_expression
|
19
|
+
query.children.find { |e| e.is_a? Expressions::Order }
|
20
|
+
end
|
21
|
+
|
22
|
+
def where_expression
|
23
|
+
query.children.find { |e| e.is_a? Expressions::Where }
|
24
|
+
end
|
25
|
+
|
26
|
+
def select_expression
|
27
|
+
query.children.find { |e| e.is_a? Expressions::Select }
|
28
|
+
end
|
29
|
+
|
30
|
+
def limit_expression
|
31
|
+
query.children.find { |e| e.is_a? Expressions::Limit }
|
32
|
+
end
|
33
|
+
|
34
|
+
def offset_expression
|
35
|
+
query.children.find { |e| e.is_a? Expressions::Offset }
|
36
|
+
end
|
37
|
+
|
38
|
+
def scroll_cursor_expression
|
39
|
+
query.children.find { |e| e.is_a? Expressions::ScrollCursor }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
module Expressions
|
4
|
+
class Expression < TreeNode
|
5
|
+
end
|
6
|
+
|
7
|
+
class Where < Expression
|
8
|
+
def initialize(criterion:, context:)
|
9
|
+
super([criterion], context)
|
10
|
+
end
|
11
|
+
|
12
|
+
def criterion
|
13
|
+
children.first
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Select < Expression
|
18
|
+
def initialize(attributes:, context:)
|
19
|
+
super(attributes.map { |a| Attribute.new(a, parent: self, context: context) }, context)
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method :projections, :children
|
23
|
+
end
|
24
|
+
|
25
|
+
class Order < Expression
|
26
|
+
def initialize(attributes:, context:)
|
27
|
+
super(attributes, context)
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :qualifiers, :children
|
31
|
+
end
|
32
|
+
|
33
|
+
class Limit < Expression
|
34
|
+
def initialize(value:, context:)
|
35
|
+
super([Value.new(value, parent: self, context: context)], context)
|
36
|
+
end
|
37
|
+
|
38
|
+
def limit
|
39
|
+
children.first
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Offset < Expression
|
44
|
+
def initialize(value:, context:)
|
45
|
+
super([Value.new(value, parent: self, context: context)], context)
|
46
|
+
end
|
47
|
+
|
48
|
+
def offset
|
49
|
+
children.first
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class ScrollCursor < Expression
|
54
|
+
def initialize(value:, context:)
|
55
|
+
super([Value.new(value, parent: self, context: context)], context)
|
56
|
+
end
|
57
|
+
|
58
|
+
def scroll_cursor
|
59
|
+
children.first
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
module Operations
|
4
|
+
class NAry < Operation
|
5
|
+
|
6
|
+
def initialize(operands:, context: nil)
|
7
|
+
super(operands, context)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class And < NAry;
|
12
|
+
end
|
13
|
+
|
14
|
+
class Or < NAry;
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
module Operations
|
4
|
+
class Unary < Operation
|
5
|
+
attr_reader :operand
|
6
|
+
|
7
|
+
def initialize(operand:, context: nil)
|
8
|
+
@operand = operand
|
9
|
+
super([operand], context)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Not < Unary
|
14
|
+
def initialize(operand:, context:)
|
15
|
+
super(operand: operand, context: context)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class OrderQualifier < Unary
|
20
|
+
def initialize(attribute:, context: nil)
|
21
|
+
attribute = attribute_component(attribute: attribute, context: context)
|
22
|
+
super(operand: attribute, context: context)
|
23
|
+
end
|
24
|
+
|
25
|
+
alias_method :attribute, :operand
|
26
|
+
end
|
27
|
+
|
28
|
+
class Ascending < OrderQualifier;
|
29
|
+
end
|
30
|
+
|
31
|
+
class Descending < OrderQualifier;
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
class Query < TreeNode
|
4
|
+
attr_accessor :errors
|
5
|
+
attr_reader :context
|
6
|
+
|
7
|
+
def initialize(context)
|
8
|
+
super()
|
9
|
+
@errors ||= Hash.new { |hash, key| hash[key] = Array.new }
|
10
|
+
@context = context
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
self.accept(AgnosticBackend::Queryable::Validator.new)
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_scroll_cursor(value)
|
22
|
+
context.scroll_cursor(value)
|
23
|
+
context.build
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
class QueryBuilder
|
4
|
+
|
5
|
+
attr_reader :index
|
6
|
+
attr_reader :query
|
7
|
+
|
8
|
+
def initialize(index)
|
9
|
+
@index = index
|
10
|
+
end
|
11
|
+
|
12
|
+
def criteria_builder
|
13
|
+
CriteriaBuilder.new(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def where(criterion)
|
17
|
+
@criterion = criterion
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def select(*attributes)
|
22
|
+
(@projections ||= []).push(*attributes)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def order(attribute, direction)
|
27
|
+
(@order_qualifiers ||= []).push build_order_qualifier(attribute, direction)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def limit(value)
|
32
|
+
@limit = value
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def offset(value)
|
37
|
+
@offset = value
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def scroll_cursor(value)
|
42
|
+
@scroll_cursor = value
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def build
|
47
|
+
query = create_query(self)
|
48
|
+
query.children << build_where_expression if @criterion
|
49
|
+
query.children << build_select_expression if @projections
|
50
|
+
query.children << build_order_expression if @order_qualifiers
|
51
|
+
query.children << build_limit_expression if @limit
|
52
|
+
query.children << build_offset_expression if @offset
|
53
|
+
query.children << build_scroll_cursor_expression if @scroll_cursor
|
54
|
+
|
55
|
+
@query = query
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def create_query(context)
|
61
|
+
raise NotImplementedError, 'AbstractMethod'
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_where_expression
|
65
|
+
Expressions::Where.new(criterion: @criterion, context: self)
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_select_expression
|
69
|
+
Expressions::Select.new(attributes: @projections, context: self)
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_order_expression
|
73
|
+
Expressions::Order.new(attributes: @order_qualifiers, context: self)
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_limit_expression
|
77
|
+
Expressions::Limit.new(value: @limit, context: self)
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_offset_expression
|
81
|
+
Expressions::Offset.new(value: @offset, context: self)
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_scroll_cursor_expression
|
85
|
+
Expressions::ScrollCursor.new(value: @scroll_cursor, context: self)
|
86
|
+
end
|
87
|
+
|
88
|
+
def build_order_qualifier(attribute, direction)
|
89
|
+
case direction
|
90
|
+
when :asc
|
91
|
+
Operations::Ascending.new(attribute: attribute, context: self)
|
92
|
+
when :desc
|
93
|
+
Operations::Descending.new(attribute: attribute, context: self)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
class ResultSet
|
4
|
+
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
attr_reader :raw_results, :query
|
8
|
+
|
9
|
+
def initialize(raw_results, query)
|
10
|
+
@raw_results, @query = raw_results, query
|
11
|
+
end
|
12
|
+
|
13
|
+
def each(&block)
|
14
|
+
filtered_results.each do |result|
|
15
|
+
block.call(transform(result))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def empty?
|
20
|
+
none?
|
21
|
+
end
|
22
|
+
|
23
|
+
def total_count
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
def offset
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def filtered_results
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
def transform(result)
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
class TreeNode
|
4
|
+
include AgnosticBackend::Utilities
|
5
|
+
# include Enumerable
|
6
|
+
|
7
|
+
attr_reader :children
|
8
|
+
attr_reader :context
|
9
|
+
|
10
|
+
def initialize(children = [], context = nil)
|
11
|
+
@children, @context = children, context
|
12
|
+
end
|
13
|
+
|
14
|
+
# def each(&block)
|
15
|
+
# block.call(self)
|
16
|
+
# children.each{|child| child.each(&block) }
|
17
|
+
# end
|
18
|
+
|
19
|
+
def ==(other)
|
20
|
+
return true if self.__id__ == other.__id__
|
21
|
+
return false if other.nil?
|
22
|
+
return false unless other.is_a? AgnosticBackend::Queryable::TreeNode
|
23
|
+
|
24
|
+
return false unless other.children.size == children.size
|
25
|
+
children_pairs = other.children.zip(children)
|
26
|
+
|
27
|
+
other.class == self.class &&
|
28
|
+
children_pairs.all? do |first_child, second_child|
|
29
|
+
first_child == second_child
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def accept(visitor)
|
34
|
+
visitor.visit(self)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def attribute_component(attribute:, context: nil)
|
40
|
+
Attribute.new(attribute, parent: self, context: context)
|
41
|
+
end
|
42
|
+
|
43
|
+
def value_component(value:, context: nil, type:)
|
44
|
+
Value.new(convert_to(type, value), parent: self, context: context)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module AgnosticBackend
|
2
|
+
module Queryable
|
3
|
+
class Validator < AgnosticBackend::Queryable::Visitor
|
4
|
+
|
5
|
+
include AgnosticBackend::Utilities
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@valid = true
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def visit_query(subject)
|
14
|
+
subject.children.each { |c| visit(c) }
|
15
|
+
@valid
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_criteria_equal(subject)
|
19
|
+
visit(subject.attribute)
|
20
|
+
visit(subject.value)
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit_criteria_not_equal(subject)
|
24
|
+
visit(subject.attribute)
|
25
|
+
visit(subject.value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def visit_criteria_greater(subject)
|
29
|
+
visit(subject.attribute)
|
30
|
+
visit(subject.value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def visit_criteria_less(subject)
|
34
|
+
visit(subject.attribute)
|
35
|
+
visit(subject.value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def visit_criteria_greater_equal(subject)
|
39
|
+
visit(subject.attribute)
|
40
|
+
visit(subject.value)
|
41
|
+
end
|
42
|
+
|
43
|
+
def visit_criteria_less_equal(subject)
|
44
|
+
visit(subject.attribute)
|
45
|
+
visit(subject.value)
|
46
|
+
end
|
47
|
+
|
48
|
+
def visit_criteria_contains(subject)
|
49
|
+
visit(subject.attribute)
|
50
|
+
visit(subject.value)
|
51
|
+
end
|
52
|
+
|
53
|
+
def visit_criteria_starts(subject)
|
54
|
+
visit(subject.attribute)
|
55
|
+
visit(subject.value)
|
56
|
+
end
|
57
|
+
|
58
|
+
def visit_criteria_greater_and_less(subject)
|
59
|
+
visit(subject.attribute)
|
60
|
+
visit(subject.left_value)
|
61
|
+
visit(subject.right_value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def visit_criteria_greater_equal_and_less(subject)
|
65
|
+
visit(subject.attribute)
|
66
|
+
visit(subject.left_value)
|
67
|
+
visit(subject.right_value)
|
68
|
+
end
|
69
|
+
|
70
|
+
def visit_criteria_greater_and_less_equal(subject)
|
71
|
+
visit(subject.attribute)
|
72
|
+
visit(subject.left_value)
|
73
|
+
visit(subject.right_value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def visit_criteria_greater_equal_and_less_equal(subject)
|
77
|
+
visit(subject.attribute)
|
78
|
+
visit(subject.left_value)
|
79
|
+
visit(subject.right_value)
|
80
|
+
end
|
81
|
+
|
82
|
+
def visit_operations_not(subject)
|
83
|
+
visit(subject.operand)
|
84
|
+
end
|
85
|
+
|
86
|
+
def visit_operations_and(subject)
|
87
|
+
subject.operands.each { |o| visit(o) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def visit_operations_or(subject)
|
91
|
+
subject.operands.each { |o| visit(o) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def visit_operations_ascending(subject)
|
95
|
+
visit(subject.attribute)
|
96
|
+
end
|
97
|
+
|
98
|
+
def visit_operations_descending(subject)
|
99
|
+
visit(subject.attribute)
|
100
|
+
end
|
101
|
+
|
102
|
+
def visit_expressions_where(subject)
|
103
|
+
visit(subject.criterion)
|
104
|
+
end
|
105
|
+
|
106
|
+
def visit_expressions_select(subject)
|
107
|
+
subject.projections.each { |c| visit(c) }
|
108
|
+
end
|
109
|
+
|
110
|
+
def visit_expressions_order(subject)
|
111
|
+
subject.qualifiers.each { |c| visit(c) }
|
112
|
+
end
|
113
|
+
|
114
|
+
def visit_expressions_limit(subject)
|
115
|
+
visit(subject.limit)
|
116
|
+
end
|
117
|
+
|
118
|
+
def visit_expressions_offset(subject)
|
119
|
+
visit(subject.offset)
|
120
|
+
end
|
121
|
+
|
122
|
+
def visit_expressions_scroll_cursor(subject)
|
123
|
+
visit(subject.scroll_cursor)
|
124
|
+
end
|
125
|
+
|
126
|
+
def visit_attribute(subject)
|
127
|
+
if value_for_key(subject.context.index.schema, subject.name).nil?
|
128
|
+
subject.context.query.errors[subject.class.name] << attribute_error(subject)
|
129
|
+
@valid = false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def visit_value(subject)
|
134
|
+
case subject.type
|
135
|
+
when :integer
|
136
|
+
unless subject.value.is_a?(Fixnum)
|
137
|
+
subject.context.query.errors[subject.class.name] << value_error(subject)
|
138
|
+
@valid = false
|
139
|
+
end
|
140
|
+
when :double
|
141
|
+
unless subject.value.is_a?(Float)
|
142
|
+
subject.context.query.errors[subject.class.name] << value_error(subject)
|
143
|
+
@valid = false
|
144
|
+
end
|
145
|
+
when :string,:string_array,:text,:text_array
|
146
|
+
unless subject.value.is_a?(String)
|
147
|
+
subject.context.query.errors[subject.class.name] << value_error(subject)
|
148
|
+
@valid = false
|
149
|
+
end
|
150
|
+
when :date
|
151
|
+
unless subject.value.is_a?(Time)
|
152
|
+
subject.context.query.errors[subject.class.name] << value_error(subject)
|
153
|
+
@valid = false
|
154
|
+
end
|
155
|
+
when :boolean
|
156
|
+
unless subject.value.is_a?(TrueClass) || subject.value.is_a?(FalseClass)
|
157
|
+
subject.context.query.errors[subject.class.name] << value_error(subject)
|
158
|
+
@valid = false
|
159
|
+
end
|
160
|
+
else
|
161
|
+
true
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def value_error(subject)
|
166
|
+
"Value #{subject.value} for #{subject.associated_attribute.name} in #{subject.parent.class.name} is defined as #{subject.type} type in schema"
|
167
|
+
end
|
168
|
+
|
169
|
+
def attribute_error(subject)
|
170
|
+
"Attribute '#{subject.name}' in #{subject.parent.class.name} missing from schema"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|