agnostic_backend 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|