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