CloudSesame 0.1.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 +4 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +76 -0
- data/Guardfile +70 -0
- data/cloud_sesame.gemspec +25 -0
- data/lib/abstract_object.rb +67 -0
- data/lib/cloud_sesame.rb +77 -0
- data/lib/cloud_sesame/config/credential.rb +8 -0
- data/lib/cloud_sesame/domain/base.rb +70 -0
- data/lib/cloud_sesame/domain/client.rb +28 -0
- data/lib/cloud_sesame/domain/config.rb +8 -0
- data/lib/cloud_sesame/domain/context.rb +35 -0
- data/lib/cloud_sesame/query/ast/and.rb +9 -0
- data/lib/cloud_sesame/query/ast/compound_array.rb +73 -0
- data/lib/cloud_sesame/query/ast/leaf.rb +8 -0
- data/lib/cloud_sesame/query/ast/literal.rb +27 -0
- data/lib/cloud_sesame/query/ast/multi_branch.rb +27 -0
- data/lib/cloud_sesame/query/ast/not.rb +13 -0
- data/lib/cloud_sesame/query/ast/operator.rb +24 -0
- data/lib/cloud_sesame/query/ast/or.rb +9 -0
- data/lib/cloud_sesame/query/ast/prefix_literal.rb +17 -0
- data/lib/cloud_sesame/query/ast/root.rb +24 -0
- data/lib/cloud_sesame/query/ast/single_branch.rb +24 -0
- data/lib/cloud_sesame/query/ast/value.rb +38 -0
- data/lib/cloud_sesame/query/builder.rb +78 -0
- data/lib/cloud_sesame/query/dsl.rb +62 -0
- data/lib/cloud_sesame/query/dsl/and.rb +19 -0
- data/lib/cloud_sesame/query/dsl/base.rb +23 -0
- data/lib/cloud_sesame/query/dsl/filter_query.rb +47 -0
- data/lib/cloud_sesame/query/dsl/literal.rb +41 -0
- data/lib/cloud_sesame/query/dsl/or.rb +19 -0
- data/lib/cloud_sesame/query/dsl/range.rb +41 -0
- data/lib/cloud_sesame/query/dsl/scope.rb +24 -0
- data/lib/cloud_sesame/query/error/missing_operator_symbol.rb +8 -0
- data/lib/cloud_sesame/query/error/missing_query.rb +8 -0
- data/lib/cloud_sesame/query/node/abstract.rb +14 -0
- data/lib/cloud_sesame/query/node/facet.rb +14 -0
- data/lib/cloud_sesame/query/node/filter_query.rb +17 -0
- data/lib/cloud_sesame/query/node/page.rb +27 -0
- data/lib/cloud_sesame/query/node/query.rb +29 -0
- data/lib/cloud_sesame/query/node/query_options.rb +37 -0
- data/lib/cloud_sesame/query/node/query_options_field.rb +20 -0
- data/lib/cloud_sesame/query/node/query_parser.rb +27 -0
- data/lib/cloud_sesame/query/node/request.rb +71 -0
- data/lib/cloud_sesame/query/node/sort.rb +37 -0
- data/spec/abstract_object_spec.rb +103 -0
- data/spec/cloud_sesame/domain/base_spec.rb +27 -0
- data/spec/cloud_sesame/domain/context_spec.rb +24 -0
- data/spec/cloud_sesame/query/ast/and_spec.rb +13 -0
- data/spec/cloud_sesame/query/ast/literal_spec.rb +37 -0
- data/spec/cloud_sesame/query/ast/multi_branch_spec.rb +65 -0
- data/spec/cloud_sesame/query/ast/operator_spec.rb +30 -0
- data/spec/cloud_sesame/query/ast/or_spec.rb +13 -0
- data/spec/cloud_sesame/query/ast/root_spec.rb +43 -0
- data/spec/cloud_sesame/query/ast/value_spec.rb +40 -0
- data/spec/cloud_sesame/query/builder_spec.rb +12 -0
- data/spec/cloud_sesame/query/dsl/base_spec.rb +31 -0
- data/spec/cloud_sesame/query/dsl/filter_query_spec.rb +158 -0
- data/spec/cloud_sesame/query/dsl_spec.rb +96 -0
- data/spec/cloud_sesame/query/node/abstract_spec.rb +19 -0
- data/spec/cloud_sesame/query/node/facet_spec.rb +42 -0
- data/spec/cloud_sesame/query/node/filter_query_spec.rb +29 -0
- data/spec/cloud_sesame/query/node/page_spec.rb +58 -0
- data/spec/cloud_sesame/query/node/query_options_field_spec.rb +27 -0
- data/spec/cloud_sesame/query/node/query_options_spec.rb +56 -0
- data/spec/cloud_sesame/query/node/query_parser_spec.rb +37 -0
- data/spec/cloud_sesame/query/node/query_spec.rb +46 -0
- data/spec/cloud_sesame/query/node/request_spec.rb +71 -0
- data/spec/cloud_sesame/query/node/sort_spec.rb +76 -0
- data/spec/cloud_sesame_spec.rb +58 -0
- data/spec/spec_helper.rb +12 -0
- metadata +218 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Domain
|
3
|
+
class Context
|
4
|
+
|
5
|
+
attr_reader :table
|
6
|
+
|
7
|
+
def initialize(table = {})
|
8
|
+
@table = table
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key, find_or_create = false)
|
12
|
+
table[key] ||= default_value(find_or_create)
|
13
|
+
end
|
14
|
+
|
15
|
+
def []=(key, value)
|
16
|
+
table[key] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
def each(&block)
|
20
|
+
table.each &block
|
21
|
+
end
|
22
|
+
|
23
|
+
def map(&block)
|
24
|
+
table.map &block
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def default_value(data)
|
30
|
+
data != true ? data : Context.new if data
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module AST
|
4
|
+
class CompoundArray < Array
|
5
|
+
# include Range
|
6
|
+
|
7
|
+
attr_accessor :scope, :parent, :literal
|
8
|
+
attr_reader :field
|
9
|
+
|
10
|
+
def field=(field)
|
11
|
+
self.parent = nil
|
12
|
+
self.literal = AST::Literal
|
13
|
+
@field = field
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_scope(scope)
|
17
|
+
self.scope = scope
|
18
|
+
return self
|
19
|
+
end
|
20
|
+
|
21
|
+
# SINGLE BRANCH OPERATOR
|
22
|
+
# =======================================
|
23
|
+
def not(*values)
|
24
|
+
self.parent = AST::Not
|
25
|
+
self.literal = AST::Literal
|
26
|
+
insert_children(values)
|
27
|
+
return self
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :is_not, :not
|
31
|
+
|
32
|
+
# PREFIX LITERAL
|
33
|
+
# =======================================
|
34
|
+
def prefix(*values)
|
35
|
+
self.literal = AST::PrefixLiteral
|
36
|
+
insert_children(values)
|
37
|
+
return self
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :start_with, :prefix
|
41
|
+
alias_method :begin_with, :prefix
|
42
|
+
|
43
|
+
# RANGE LITERAL
|
44
|
+
# =======================================
|
45
|
+
# def range
|
46
|
+
# self.literal = AST::PrefixLiteral
|
47
|
+
# insert_children(values)
|
48
|
+
# return self
|
49
|
+
# end
|
50
|
+
|
51
|
+
# alias_method :start_with, :prefix
|
52
|
+
|
53
|
+
def insert_children(values = [])
|
54
|
+
values.each do |value|
|
55
|
+
if parent
|
56
|
+
self << (node = parent.new scope.context)
|
57
|
+
node.child = literal.new(field, value, options)
|
58
|
+
else
|
59
|
+
self << literal.new(field, value, options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def options
|
67
|
+
scope.context[:fields][field]
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module AST
|
4
|
+
class Literal < SingleBranch
|
5
|
+
|
6
|
+
attr_accessor :field
|
7
|
+
attr_reader :value, :options
|
8
|
+
|
9
|
+
def initialize(field, value, options = {})
|
10
|
+
@field = field
|
11
|
+
@value = Value.new(value)
|
12
|
+
@options = options
|
13
|
+
(options[:included] ||= []) << value
|
14
|
+
end
|
15
|
+
|
16
|
+
def value=(value)
|
17
|
+
@value = Value.new(value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def compile
|
21
|
+
"#{ field }:#{ value.compile }"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module AST
|
4
|
+
class MultiBranch
|
5
|
+
include DSL::Base
|
6
|
+
include DSL::FilterQuery
|
7
|
+
include DSL::Scope
|
8
|
+
|
9
|
+
attr_reader :context
|
10
|
+
|
11
|
+
def initialize(context, &block)
|
12
|
+
@context = context
|
13
|
+
instance_eval &block if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def children
|
17
|
+
@children ||= CompoundArray.new.set_scope self
|
18
|
+
end
|
19
|
+
|
20
|
+
def compile_children
|
21
|
+
children.map(&:compile).join(' ')
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module AST
|
4
|
+
class Operator < MultiBranch
|
5
|
+
|
6
|
+
# Operator Symbol Writer
|
7
|
+
def self.symbol=(symbol)
|
8
|
+
@symbol = symbol
|
9
|
+
end
|
10
|
+
|
11
|
+
# Operator Symbol Getter
|
12
|
+
def self.symbol
|
13
|
+
@symbol
|
14
|
+
end
|
15
|
+
|
16
|
+
def compile
|
17
|
+
raise Error::MissingOperatorSymbol if self.class.symbol.nil?
|
18
|
+
"(#{ self.class.symbol } #{ compile_children })" unless children.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module AST
|
4
|
+
class PrefixLiteral < Literal
|
5
|
+
|
6
|
+
def compile
|
7
|
+
"(prefix field=#{ escape(field) } #{ value.compile })"
|
8
|
+
end
|
9
|
+
|
10
|
+
def escape(data = "")
|
11
|
+
"'#{ data.to_s.gsub(/\'/) { "\\'" } }'"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module AST
|
4
|
+
class Root < MultiBranch
|
5
|
+
|
6
|
+
def compile
|
7
|
+
if children.size > 1
|
8
|
+
join_by_default_operator.compile
|
9
|
+
else
|
10
|
+
compile_children
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def join_by_default_operator
|
17
|
+
(default = And.new context).children.concat children
|
18
|
+
default
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module AST
|
4
|
+
class SingleBranch
|
5
|
+
|
6
|
+
attr_accessor :child
|
7
|
+
attr_reader :context
|
8
|
+
|
9
|
+
def initialize(context, &block)
|
10
|
+
@context = context
|
11
|
+
instance_eval &block if block_given?
|
12
|
+
end
|
13
|
+
|
14
|
+
def child=(object)
|
15
|
+
if object.kind_of? Literal
|
16
|
+
(object.options[:excluded] ||= []) << object.options[:included].delete(object.value.data)
|
17
|
+
end
|
18
|
+
@child = object
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
module AST
|
4
|
+
class Value < Leaf
|
5
|
+
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
def initialize(data)
|
9
|
+
@data = data
|
10
|
+
end
|
11
|
+
|
12
|
+
def compile
|
13
|
+
format(data)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def format(data)
|
19
|
+
range?(data) || digits?(data) ? data : escape(data)
|
20
|
+
end
|
21
|
+
|
22
|
+
def range?(data)
|
23
|
+
data =~ /^[\[\{].*[\]\}]$/
|
24
|
+
end
|
25
|
+
|
26
|
+
def digits?(data)
|
27
|
+
data.to_s =~ /^\d+(.\d+)?$/
|
28
|
+
end
|
29
|
+
|
30
|
+
# "hello" => "'hello'"
|
31
|
+
def escape(data = "")
|
32
|
+
"'#{ data.to_s.gsub(/\'/) { "\\'" } }'"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module CloudSesame
|
2
|
+
module Query
|
3
|
+
class Builder
|
4
|
+
include DSL::Base
|
5
|
+
include DSL::FilterQuery
|
6
|
+
|
7
|
+
attr_accessor :context, :searchable_class
|
8
|
+
|
9
|
+
def initialize(default_context, searchable_class)
|
10
|
+
@context = default_context
|
11
|
+
@searchable_class = searchable_class
|
12
|
+
end
|
13
|
+
|
14
|
+
def request
|
15
|
+
@request ||= Node::Request.new context.dup
|
16
|
+
end
|
17
|
+
|
18
|
+
def reset
|
19
|
+
@request = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"#<CloudSesame::Query::Builder:#{ object_id } #{ request.compile }>"
|
24
|
+
end
|
25
|
+
|
26
|
+
# CHAINABLE METHODS
|
27
|
+
# =========================================
|
28
|
+
|
29
|
+
def query(string)
|
30
|
+
request.query.query = string
|
31
|
+
return self
|
32
|
+
end
|
33
|
+
|
34
|
+
def terms(*terms)
|
35
|
+
request.query.terms.concat terms
|
36
|
+
return self
|
37
|
+
end
|
38
|
+
|
39
|
+
def exclude_terms(*terms)
|
40
|
+
request.query.terms.concat terms.map { |t| "-#{ t }" }
|
41
|
+
return self
|
42
|
+
end
|
43
|
+
|
44
|
+
def page(value)
|
45
|
+
request.page.page = value.to_i
|
46
|
+
return self
|
47
|
+
end
|
48
|
+
|
49
|
+
def size(value)
|
50
|
+
request.page.size = value.to_i
|
51
|
+
return self
|
52
|
+
end
|
53
|
+
|
54
|
+
def sort(hash = {})
|
55
|
+
hash.each { |key, value| request.sort[key] = value }
|
56
|
+
return self
|
57
|
+
end
|
58
|
+
|
59
|
+
# ENDING METHODS
|
60
|
+
# =========================================
|
61
|
+
|
62
|
+
def search
|
63
|
+
compiled = request.compile
|
64
|
+
raise Error::MissingQuery.new("Query can not be empty!") unless compiled[:query] && !compiled[:query].empty?
|
65
|
+
result = searchable_class.cloudsearch.client.search compiled
|
66
|
+
reset
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def method_scope
|
73
|
+
request.filter_query.root
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# module CloudSesame
|
2
|
+
# module Query
|
3
|
+
# module DSL
|
4
|
+
|
5
|
+
# # CLAUSE: AND
|
6
|
+
# # =========================================
|
7
|
+
# def and(&block)
|
8
|
+
# filter_query.children << AST::And.new(context, &block)
|
9
|
+
# return filter_query
|
10
|
+
# end
|
11
|
+
|
12
|
+
# alias_method :all, :and
|
13
|
+
# alias_method :and!, :and
|
14
|
+
# alias_method :+, :and
|
15
|
+
|
16
|
+
# # CLAUSE: OR
|
17
|
+
# # =========================================
|
18
|
+
# def or(&block)
|
19
|
+
# filter_query.children << AST::Or.new(context, &block)
|
20
|
+
# return filter_query
|
21
|
+
# end
|
22
|
+
|
23
|
+
# alias_method :any, :or
|
24
|
+
# alias_method :or!, :or
|
25
|
+
|
26
|
+
# # CLAUSE: LITERAL
|
27
|
+
# # =========================================
|
28
|
+
# def literal(field, value, options = {})
|
29
|
+
# node = AST::Literal.new(field, value, options)
|
30
|
+
# filter_query.children << node
|
31
|
+
# node
|
32
|
+
# end
|
33
|
+
|
34
|
+
# def prefix(literals)
|
35
|
+
# literals.each { |literal| literal.options[:prefix] = true }
|
36
|
+
# return filter_query
|
37
|
+
# end
|
38
|
+
|
39
|
+
# private
|
40
|
+
|
41
|
+
# def filter_query
|
42
|
+
# self
|
43
|
+
# end
|
44
|
+
|
45
|
+
# def scopes
|
46
|
+
# filter_query.context[:scopes]
|
47
|
+
# end
|
48
|
+
|
49
|
+
# def method_missing(field, *values, &block)
|
50
|
+
# if context[:fields] && (options = context[:fields][field])
|
51
|
+
# values.map { |value| literal(field, value, options) }
|
52
|
+
# elsif scope && (callback = scope[field])
|
53
|
+
# filter_query.instance_exec *values, &callback
|
54
|
+
# return filter_query
|
55
|
+
# else
|
56
|
+
# super
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
# end
|