skydb 0.2.3 → 0.3.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 +15 -0
- data/README.md +165 -1
- data/lib/skydb.rb +18 -61
- data/lib/skydb/client.rb +186 -186
- data/lib/skydb/event.rb +47 -76
- data/lib/skydb/property.rb +34 -67
- data/lib/skydb/table.rb +121 -41
- data/lib/skydb/version.rb +1 -1
- data/test/integration/client_test.rb +88 -0
- data/test/test_helper.rb +3 -51
- data/test/unit/client_test.rb +135 -32
- metadata +17 -278
- data/bin/sky +0 -89
- data/lib/ext/hash.rb +0 -11
- data/lib/ext/string.rb +0 -11
- data/lib/ext/treetop.rb +0 -19
- data/lib/skydb/action.rb +0 -76
- data/lib/skydb/import.rb +0 -7
- data/lib/skydb/import/importer.rb +0 -435
- data/lib/skydb/import/transforms/apache.yml +0 -4
- data/lib/skydb/import/transforms/sky.yml +0 -28
- data/lib/skydb/import/transforms/snowplow.yml +0 -1
- data/lib/skydb/import/translator.rb +0 -119
- data/lib/skydb/message.rb +0 -146
- data/lib/skydb/message/add_action.rb +0 -53
- data/lib/skydb/message/add_event.rb +0 -72
- data/lib/skydb/message/add_property.rb +0 -55
- data/lib/skydb/message/create_table.rb +0 -64
- data/lib/skydb/message/delete_table.rb +0 -66
- data/lib/skydb/message/get_action.rb +0 -55
- data/lib/skydb/message/get_actions.rb +0 -38
- data/lib/skydb/message/get_properties.rb +0 -38
- data/lib/skydb/message/get_property.rb +0 -55
- data/lib/skydb/message/get_table.rb +0 -74
- data/lib/skydb/message/get_tables.rb +0 -43
- data/lib/skydb/message/lookup.rb +0 -79
- data/lib/skydb/message/lua/aggregate.rb +0 -63
- data/lib/skydb/message/multi.rb +0 -57
- data/lib/skydb/message/next_actions.rb +0 -55
- data/lib/skydb/message/ping.rb +0 -32
- data/lib/skydb/property/type.rb +0 -40
- data/lib/skydb/query.rb +0 -183
- data/lib/skydb/query/after_condition.rb +0 -104
- data/lib/skydb/query/ast/selection_field_syntax_node.rb +0 -26
- data/lib/skydb/query/ast/selection_fields_syntax_node.rb +0 -16
- data/lib/skydb/query/ast/selection_group_syntax_node.rb +0 -16
- data/lib/skydb/query/ast/selection_groups_syntax_node.rb +0 -16
- data/lib/skydb/query/condition.rb +0 -113
- data/lib/skydb/query/on_condition.rb +0 -53
- data/lib/skydb/query/selection.rb +0 -398
- data/lib/skydb/query/selection_field.rb +0 -99
- data/lib/skydb/query/selection_fields_grammar.treetop +0 -46
- data/lib/skydb/query/selection_fields_parse_error.rb +0 -30
- data/lib/skydb/query/selection_group.rb +0 -78
- data/lib/skydb/query/selection_groups_grammar.treetop +0 -31
- data/lib/skydb/query/selection_groups_parse_error.rb +0 -30
- data/lib/skydb/query/validation_error.rb +0 -8
- data/lib/skydb/timestamp.rb +0 -22
- data/test/integration/query_test.rb +0 -102
- data/test/unit/event_test.rb +0 -32
- data/test/unit/import/importer_test.rb +0 -208
- data/test/unit/import/translator_test.rb +0 -88
- data/test/unit/message/add_action_message_test.rb +0 -34
- data/test/unit/message/add_event_message_test.rb +0 -35
- data/test/unit/message/add_property_message_test.rb +0 -41
- data/test/unit/message/create_table_message_test.rb +0 -34
- data/test/unit/message/delete_table_message_test.rb +0 -34
- data/test/unit/message/get_action_message_test.rb +0 -34
- data/test/unit/message/get_actions_message_test.rb +0 -18
- data/test/unit/message/get_properties_message_test.rb +0 -18
- data/test/unit/message/get_property_message_test.rb +0 -34
- data/test/unit/message/get_table_message_test.rb +0 -19
- data/test/unit/message/get_tables_message_test.rb +0 -18
- data/test/unit/message/lookup_message_test.rb +0 -27
- data/test/unit/message/lua_aggregate_message_test.rb +0 -19
- data/test/unit/message/multi_message_test.rb +0 -22
- data/test/unit/message/next_action_message_test.rb +0 -34
- data/test/unit/message/ping_message_test.rb +0 -18
- data/test/unit/message_test.rb +0 -15
- data/test/unit/query/after_test.rb +0 -89
- data/test/unit/query/on_test.rb +0 -71
- data/test/unit/query/selection_test.rb +0 -273
- data/test/unit/query_test.rb +0 -182
- data/test/unit/skydb_test.rb +0 -20
@@ -1,26 +0,0 @@
|
|
1
|
-
class SkyDB
|
2
|
-
class Query
|
3
|
-
class Ast
|
4
|
-
module SelectionFieldSyntaxNode
|
5
|
-
# Generates the SelectionField object from the node.
|
6
|
-
def generate
|
7
|
-
field = SkyDB::Query::SelectionField.new()
|
8
|
-
|
9
|
-
# If there is an expression present then use it.
|
10
|
-
if respond_to?('expression')
|
11
|
-
field.expression = expression.text_value
|
12
|
-
|
13
|
-
# Otherwise we'll typically use the whole value unless there is an
|
14
|
-
# aggregation type mentioned. An example of this is: "count()".
|
15
|
-
elsif !respond_to?('aggregation_type')
|
16
|
-
field.expression = text_value
|
17
|
-
end
|
18
|
-
|
19
|
-
field.alias_name = alias_name.text_value if respond_to?('alias_name')
|
20
|
-
field.aggregation_type = aggregation_type.text_value.downcase.to_sym if respond_to?('aggregation_type')
|
21
|
-
return field
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class SkyDB
|
2
|
-
class Query
|
3
|
-
class Ast
|
4
|
-
module SelectionFieldsSyntaxNode
|
5
|
-
# Generates a list of selection fields.
|
6
|
-
def generate
|
7
|
-
fields = []
|
8
|
-
Treetop.search(self, SelectionFieldSyntaxNode).each do |field_node|
|
9
|
-
fields << field_node.generate()
|
10
|
-
end
|
11
|
-
return fields
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class SkyDB
|
2
|
-
class Query
|
3
|
-
class Ast
|
4
|
-
module SelectionGroupSyntaxNode
|
5
|
-
# Generates the SelectionGroup object from the node.
|
6
|
-
def generate
|
7
|
-
group = SkyDB::Query::SelectionGroup.new(
|
8
|
-
:expression => (respond_to?('expression') ? expression.text_value : text_value)
|
9
|
-
)
|
10
|
-
group.alias_name = alias_name.text_value if respond_to?('alias_name')
|
11
|
-
return group
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class SkyDB
|
2
|
-
class Query
|
3
|
-
class Ast
|
4
|
-
module SelectionGroupsSyntaxNode
|
5
|
-
# Generates a list of selection groups.
|
6
|
-
def generate
|
7
|
-
groups = []
|
8
|
-
Treetop.search(self, SelectionGroupSyntaxNode).each do |group_node|
|
9
|
-
groups << group_node.generate()
|
10
|
-
end
|
11
|
-
return groups
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,113 +0,0 @@
|
|
1
|
-
class SkyDB
|
2
|
-
class Query
|
3
|
-
# The Condition class is the base class for all query classes that limit
|
4
|
-
# the selection.
|
5
|
-
class Condition
|
6
|
-
##########################################################################
|
7
|
-
#
|
8
|
-
# Constructor
|
9
|
-
#
|
10
|
-
##########################################################################
|
11
|
-
|
12
|
-
def initialize(options={})
|
13
|
-
self.action = options[:action]
|
14
|
-
self.function_name = options[:function_name]
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
##########################################################################
|
19
|
-
#
|
20
|
-
# Attributes
|
21
|
-
#
|
22
|
-
##########################################################################
|
23
|
-
|
24
|
-
# The function name to use when generating the code.
|
25
|
-
attr_accessor :function_name
|
26
|
-
|
27
|
-
# The action to match. If set to a string or id then it is automatically
|
28
|
-
# wrapped in an Action object.
|
29
|
-
attr_reader :action
|
30
|
-
|
31
|
-
def action=(value)
|
32
|
-
if value.is_a?(String)
|
33
|
-
@action = SkyDB::Action.new(:name => value)
|
34
|
-
elsif value.is_a?(Fixnum)
|
35
|
-
@action = SkyDB::Action.new(:id => value)
|
36
|
-
elsif value.is_a?(SkyDB::Action) || value == :enter
|
37
|
-
@action = value
|
38
|
-
else
|
39
|
-
@action = nil
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
##########################################################################
|
45
|
-
#
|
46
|
-
# Methods
|
47
|
-
#
|
48
|
-
##########################################################################
|
49
|
-
|
50
|
-
##################################
|
51
|
-
# Validation
|
52
|
-
##################################
|
53
|
-
|
54
|
-
# Validates that the object is correct before executing a codegen.
|
55
|
-
def validate!
|
56
|
-
# Require the action identifier.
|
57
|
-
if action.nil? || action == :enter || action.id.to_i == 0
|
58
|
-
raise SkyDB::Query::ValidationError.new("Action with non-zero identifier required.")
|
59
|
-
end
|
60
|
-
|
61
|
-
# Require the function name. This should be set automatically by the
|
62
|
-
# query.
|
63
|
-
if function_name.to_s.index(/^\w+$/).nil?
|
64
|
-
raise SkyDB::Query::ValidationError.new("Invalid function name '#{function_name.to_s}'.")
|
65
|
-
end
|
66
|
-
|
67
|
-
return nil
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
##################################
|
72
|
-
# Codegen
|
73
|
-
##################################
|
74
|
-
|
75
|
-
# Generates Lua code to match a given action.
|
76
|
-
def codegen(options={})
|
77
|
-
return "function #{function_name.to_s}(cursor, data) return false end\n"
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
####################################
|
82
|
-
# Serialization
|
83
|
-
####################################
|
84
|
-
|
85
|
-
# Serializes the condition into a JSON string.
|
86
|
-
def to_json(*a); to_hash.to_json(*a); end
|
87
|
-
|
88
|
-
# Serializes the condition into a hash.
|
89
|
-
def to_hash(*a)
|
90
|
-
json = {}
|
91
|
-
json['type'] = self.class.to_s.split("::").last.gsub('Condition', '').downcase
|
92
|
-
if action.is_a?(SkyDB::Action)
|
93
|
-
json['action'] = action.to_hash(*a)
|
94
|
-
elsif action.is_a?(Symbol)
|
95
|
-
json['action'] = action
|
96
|
-
end
|
97
|
-
json
|
98
|
-
end
|
99
|
-
|
100
|
-
# Deserializes the condition from a hash.
|
101
|
-
def from_hash(hash, *a)
|
102
|
-
return nil if hash.nil?
|
103
|
-
if hash['action'] == "enter"
|
104
|
-
self.action = hash['action'].to_sym
|
105
|
-
else
|
106
|
-
self.action = SkyDB::Action.new.from_hash(hash['action'], *a)
|
107
|
-
end
|
108
|
-
return self
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
@@ -1,53 +0,0 @@
|
|
1
|
-
class SkyDB
|
2
|
-
class Query
|
3
|
-
# The 'on' condition filters a selection and leaves the cursor on the
|
4
|
-
# current matching event.
|
5
|
-
class OnCondition < SkyDB::Query::Condition
|
6
|
-
##########################################################################
|
7
|
-
#
|
8
|
-
# Constructor
|
9
|
-
#
|
10
|
-
##########################################################################
|
11
|
-
|
12
|
-
def initialize(action=nil, options={})
|
13
|
-
options.merge!(action.is_a?(Hash) ? action : {:action => action})
|
14
|
-
super(options)
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
##########################################################################
|
19
|
-
#
|
20
|
-
# Methods
|
21
|
-
#
|
22
|
-
##########################################################################
|
23
|
-
|
24
|
-
##################################
|
25
|
-
# Codegen
|
26
|
-
##################################
|
27
|
-
|
28
|
-
# Generates Lua code to match a given action.
|
29
|
-
def codegen(options={})
|
30
|
-
header, body, footer = "function #{function_name.to_s}(cursor, data)\n", [], "end\n"
|
31
|
-
|
32
|
-
# If the action is :enter then just check for the beginning of a session.
|
33
|
-
if action == :enter
|
34
|
-
body << "return (cursor.session_event_index == 0)"
|
35
|
-
else
|
36
|
-
# Only move to the next event if directed to by the options.
|
37
|
-
body << "if cursor:eos() or cursor:eof() then return false end"
|
38
|
-
body << "repeat"
|
39
|
-
body << " if cursor.event.action_id == #{action.id.to_i} then"
|
40
|
-
body << " return true"
|
41
|
-
body << " end"
|
42
|
-
body << "until not cursor:next()"
|
43
|
-
body << "return false"
|
44
|
-
end
|
45
|
-
|
46
|
-
# Indent body and return.
|
47
|
-
body.map! {|line| " " + line}
|
48
|
-
return header + body.join("\n") + "\n" + footer
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
@@ -1,398 +0,0 @@
|
|
1
|
-
require 'skydb/query/selection_fields_parse_error'
|
2
|
-
require 'skydb/query/selection_field'
|
3
|
-
|
4
|
-
require 'skydb/query/selection_groups_parse_error'
|
5
|
-
require 'skydb/query/selection_group'
|
6
|
-
|
7
|
-
require 'skydb/query/ast/selection_fields_syntax_node'
|
8
|
-
require 'skydb/query/ast/selection_field_syntax_node'
|
9
|
-
require 'skydb/query/ast/selection_groups_syntax_node'
|
10
|
-
require 'skydb/query/ast/selection_group_syntax_node'
|
11
|
-
require 'skydb/query/selection_fields_grammar'
|
12
|
-
require 'skydb/query/selection_groups_grammar'
|
13
|
-
|
14
|
-
class SkyDB
|
15
|
-
class Query
|
16
|
-
# The selection object contains a list of all fields and their aliases.
|
17
|
-
# Selection fields can include simple properties as well as aggregation
|
18
|
-
# functions.
|
19
|
-
class Selection
|
20
|
-
##########################################################################
|
21
|
-
#
|
22
|
-
# Static Methods
|
23
|
-
#
|
24
|
-
##########################################################################
|
25
|
-
|
26
|
-
# Parses a string into a list of selection fields.
|
27
|
-
#
|
28
|
-
# @param [String] str A formatted list of fields to select.
|
29
|
-
#
|
30
|
-
# @return [Array] An array of selection fields.
|
31
|
-
def self.parse_fields(str)
|
32
|
-
# Parse the selection fields string.
|
33
|
-
parser = SelectionFieldsGrammarParser.new()
|
34
|
-
ast = parser.parse(str)
|
35
|
-
|
36
|
-
# If there was a problem then throw a parse error.
|
37
|
-
if ast.nil?
|
38
|
-
raise SkyDB::Query::SelectionFieldsParseError.new(parser.failure_reason,
|
39
|
-
:line => parser.failure_line,
|
40
|
-
:column => parser.failure_column
|
41
|
-
)
|
42
|
-
end
|
43
|
-
|
44
|
-
return ast.generate
|
45
|
-
end
|
46
|
-
|
47
|
-
# Parses a string into a list of selection groups.
|
48
|
-
#
|
49
|
-
# @param [String] str A formatted list of fields to group by.
|
50
|
-
#
|
51
|
-
# @return [Array] An array of selection groups.
|
52
|
-
def self.parse_groups(str)
|
53
|
-
# Parse the selection groups string.
|
54
|
-
parser = SelectionGroupsGrammarParser.new()
|
55
|
-
ast = parser.parse(str)
|
56
|
-
|
57
|
-
# If there was a problem then throw a parse error.
|
58
|
-
if ast.nil?
|
59
|
-
raise SkyDB::Query::SelectionGroupsParseError.new(parser.failure_reason,
|
60
|
-
:line => parser.failure_line,
|
61
|
-
:column => parser.failure_column
|
62
|
-
)
|
63
|
-
end
|
64
|
-
|
65
|
-
return ast.generate
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
##########################################################################
|
70
|
-
#
|
71
|
-
# Constructor
|
72
|
-
#
|
73
|
-
##########################################################################
|
74
|
-
|
75
|
-
def initialize(options={})
|
76
|
-
self.query = options[:query]
|
77
|
-
self.fields = options[:fields] || []
|
78
|
-
self.groups = options[:groups] || []
|
79
|
-
self.conditions = options[:conditions] || []
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
|
-
##########################################################################
|
84
|
-
#
|
85
|
-
# Attributes
|
86
|
-
#
|
87
|
-
##########################################################################
|
88
|
-
|
89
|
-
# The query this selection is attached to.
|
90
|
-
attr_accessor :query
|
91
|
-
|
92
|
-
# A list of fields that will be returned from the server.
|
93
|
-
attr_accessor :fields
|
94
|
-
|
95
|
-
# A list of expressions to group the returned data by.
|
96
|
-
attr_accessor :groups
|
97
|
-
|
98
|
-
# A list of conditions that must be fulfilled before performing a
|
99
|
-
# selection.
|
100
|
-
attr_accessor :conditions
|
101
|
-
|
102
|
-
|
103
|
-
##########################################################################
|
104
|
-
#
|
105
|
-
# Methods
|
106
|
-
#
|
107
|
-
##########################################################################
|
108
|
-
|
109
|
-
####################################
|
110
|
-
# Helpers
|
111
|
-
####################################
|
112
|
-
|
113
|
-
# Adds a list of fields to the selection.
|
114
|
-
#
|
115
|
-
# @param [String] args A list of fields to add to the selection.
|
116
|
-
#
|
117
|
-
# @return [Selection] The selection object is returned.
|
118
|
-
def select(*args)
|
119
|
-
args.each do |arg|
|
120
|
-
if arg.is_a?(String)
|
121
|
-
self.fields = self.fields.concat(SkyDB::Query::Selection.parse_fields(arg))
|
122
|
-
elsif arg.is_a?(Symbol)
|
123
|
-
self.fields << SelectionField.new(:expression => arg.to_s)
|
124
|
-
else
|
125
|
-
raise "Invalid selection argument: #{arg} (#{arg.class})"
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
return self
|
130
|
-
end
|
131
|
-
|
132
|
-
# Adds one or more grouping fields to the selection of the query.
|
133
|
-
#
|
134
|
-
# @param [String] args A list of groups to add to the selection.
|
135
|
-
#
|
136
|
-
# @return [Selection] The selection object is returned.
|
137
|
-
def group_by(*args)
|
138
|
-
args.each do |arg|
|
139
|
-
if arg.is_a?(String)
|
140
|
-
self.groups = self.groups.concat(SkyDB::Query::Selection.parse_groups(arg))
|
141
|
-
elsif arg.is_a?(Symbol)
|
142
|
-
self.groups << SelectionGroup.new(:expression => arg.to_s)
|
143
|
-
else
|
144
|
-
raise "Invalid group by argument: #{arg} (#{arg.class})"
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
return self
|
149
|
-
end
|
150
|
-
|
151
|
-
# Adds an 'after' condition to the query.
|
152
|
-
#
|
153
|
-
# @param [Hash] options The options to pass to the 'after' condition.
|
154
|
-
#
|
155
|
-
# @return [Query] The query object is returned.
|
156
|
-
def after(options={})
|
157
|
-
conditions << SkyDB::Query::AfterCondition.new(options)
|
158
|
-
return self
|
159
|
-
end
|
160
|
-
|
161
|
-
# Adds an 'on' condition to the query.
|
162
|
-
#
|
163
|
-
# @param [Hash] options The options to pass to the 'on' condition.
|
164
|
-
#
|
165
|
-
# @return [Query] The query object is returned.
|
166
|
-
def on(options={})
|
167
|
-
conditions << SkyDB::Query::OnCondition.new(options)
|
168
|
-
return self
|
169
|
-
end
|
170
|
-
|
171
|
-
# Executes the parent query.
|
172
|
-
def execute()
|
173
|
-
return query.execute
|
174
|
-
end
|
175
|
-
|
176
|
-
|
177
|
-
####################################
|
178
|
-
# Validation
|
179
|
-
####################################
|
180
|
-
|
181
|
-
# Validates that all the elements of the query are valid.
|
182
|
-
def validate!
|
183
|
-
# Require that at least one field exist.
|
184
|
-
if fields.length == 0
|
185
|
-
raise SkyDB::Query::ValidationError.new("At least one selection field is required for #{self.inspect}.")
|
186
|
-
end
|
187
|
-
|
188
|
-
fields.each do |field|
|
189
|
-
field.validate!
|
190
|
-
end
|
191
|
-
|
192
|
-
groups.each do |group|
|
193
|
-
group.validate!
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
|
198
|
-
####################################
|
199
|
-
# Codegen
|
200
|
-
####################################
|
201
|
-
|
202
|
-
# Generates Lua code for the entire selection including conditions and
|
203
|
-
# merging.
|
204
|
-
def codegen
|
205
|
-
return [
|
206
|
-
codegen_select(),
|
207
|
-
codegen_select_all(),
|
208
|
-
codegen_merge()
|
209
|
-
].join("\n")
|
210
|
-
end
|
211
|
-
|
212
|
-
# Generates Lua code for the aggregation based on the selection.
|
213
|
-
def codegen_select
|
214
|
-
header, body, footer = "function select(cursor, data)\n", [], "end\n"
|
215
|
-
|
216
|
-
# Setup target object.
|
217
|
-
body << "target = data"
|
218
|
-
body << "" if groups.length > 0
|
219
|
-
|
220
|
-
# Initialize groups.
|
221
|
-
groups.each do |group|
|
222
|
-
body << "group_value = #{group.accessor}"
|
223
|
-
body << "if cursor:eos() or cursor:eof() then group_value = 'exit' end" if group.expression == 'action_id'
|
224
|
-
body << "if target[group_value] == nil then"
|
225
|
-
body << " target[group_value] = {}"
|
226
|
-
body << "end"
|
227
|
-
body << "target = target[group_value]"
|
228
|
-
body << ""
|
229
|
-
end
|
230
|
-
|
231
|
-
# Generate the assignment for each field.
|
232
|
-
fields.each do |field|
|
233
|
-
alias_name = field.target_name
|
234
|
-
|
235
|
-
case field.aggregation_type
|
236
|
-
when nil
|
237
|
-
body << "target.#{alias_name} = #{field.accessor}"
|
238
|
-
when :count
|
239
|
-
body << "target.#{alias_name} = (target.#{alias_name} or 0) + 1"
|
240
|
-
when :sum
|
241
|
-
body << "target.#{alias_name} = (target.#{alias_name} or 0) + #{field.accessor}"
|
242
|
-
when :min
|
243
|
-
body << "if(target.#{alias_name} == nil or target.#{alias_name} > #{field.accessor}) then"
|
244
|
-
body << " target.#{alias_name} = #{field.accessor}"
|
245
|
-
body << "end"
|
246
|
-
when :max
|
247
|
-
body << "if(target.#{alias_name} == nil or target.#{alias_name} < #{field.accessor}) then"
|
248
|
-
body << " target.#{alias_name} = #{field.accessor}"
|
249
|
-
body << "end"
|
250
|
-
else
|
251
|
-
raise StandardError.new("Invalid aggregation type: #{field.aggregation_type}")
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
# Indent body and return.
|
256
|
-
body.map! {|line| " " + line}
|
257
|
-
return header + body.join("\n") + "\n" + footer
|
258
|
-
end
|
259
|
-
|
260
|
-
# Generates Lua code for the aggregation based on the selection.
|
261
|
-
def codegen_select_all
|
262
|
-
header, body, footer = "function select_all(cursor, data)\n", [], "end\n"
|
263
|
-
|
264
|
-
# Generate the invocation of the conditions.
|
265
|
-
conditional_functions = codegen_conditional_functions()
|
266
|
-
conditionals = conditions.map {|condition| "#{condition.function_name}(cursor, data)"}.join(' and ')
|
267
|
-
conditionals = "true" if conditions.length == 0
|
268
|
-
|
269
|
-
body << "while cursor:next_session() do"
|
270
|
-
body << " while cursor:next() do"
|
271
|
-
body << " if #{conditionals} then"
|
272
|
-
body << " select(cursor, data)"
|
273
|
-
body << " end"
|
274
|
-
body << " end"
|
275
|
-
body << "end"
|
276
|
-
|
277
|
-
# Indent body and return.
|
278
|
-
body.map! {|line| " " + line}
|
279
|
-
return conditional_functions + "\n" + header + body.join("\n") + "\n" + footer
|
280
|
-
end
|
281
|
-
|
282
|
-
# Generates Lua code for the conditional functions.
|
283
|
-
def codegen_conditional_functions
|
284
|
-
code = []
|
285
|
-
|
286
|
-
# Generate condition functions.
|
287
|
-
conditions.each_with_index do |condition, index|
|
288
|
-
condition.function_name ||= "__condition#{query.nextseq}"
|
289
|
-
code << condition.codegen
|
290
|
-
end
|
291
|
-
|
292
|
-
return code.join("\n")
|
293
|
-
end
|
294
|
-
|
295
|
-
|
296
|
-
# Generates Lua code for the merge function.
|
297
|
-
def codegen_merge
|
298
|
-
header, body, footer = "function merge(results, data)\n", [], "end\n"
|
299
|
-
|
300
|
-
# Open group loops.
|
301
|
-
groups.each_with_index do |group, index|
|
302
|
-
data_item = "data" + (0...index).to_a.map {|i| "[k#{i}]"}.join('')
|
303
|
-
results_item = "results" + (0..index).to_a.map {|i| "[k#{i}]"}.join('')
|
304
|
-
body << "#{' ' * index}for k#{index},v#{index} in pairs(#{data_item}) do"
|
305
|
-
body << "#{' ' * index} if #{results_item} == nil then #{results_item} = {} end"
|
306
|
-
end
|
307
|
-
|
308
|
-
indent = ' ' * groups.length
|
309
|
-
body << "#{indent}a = results" + (0...groups.length).to_a.map {|i| "[k#{i}]"}.join('')
|
310
|
-
body << "#{indent}b = data" + (0...groups.length).to_a.map {|i| "[k#{i}]"}.join('')
|
311
|
-
|
312
|
-
# Generate the merge for each field.
|
313
|
-
fields.each do |field|
|
314
|
-
alias_name = field.target_name
|
315
|
-
|
316
|
-
case field.aggregation_type
|
317
|
-
when nil
|
318
|
-
body << "#{indent}a.#{alias_name} = b.#{alias_name}"
|
319
|
-
when :count
|
320
|
-
body << "#{indent}a.#{alias_name} = (a.#{alias_name} or 0) + (b.#{alias_name} or 0)"
|
321
|
-
when :sum
|
322
|
-
body << "#{indent}a.#{alias_name} = (a.#{alias_name} or 0) + (b.#{alias_name} or 0)"
|
323
|
-
when :min
|
324
|
-
body << "#{indent}if(a.#{alias_name} == nil or a.#{alias_name} > b.#{alias_name}) then"
|
325
|
-
body << "#{indent} a.#{alias_name} = b.#{alias_name}"
|
326
|
-
body << "#{indent}end"
|
327
|
-
when :max
|
328
|
-
body << "#{indent}if(a.#{alias_name} == nil or a.#{alias_name} < b.#{alias_name}) then"
|
329
|
-
body << "#{indent} a.#{alias_name} = b.#{alias_name}"
|
330
|
-
body << "#{indent}end"
|
331
|
-
else
|
332
|
-
raise StandardError.new("Invalid aggregation type: #{field.aggregation_type}")
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
# Close group loops.
|
337
|
-
groups.reverse.each_with_index do |group, index|
|
338
|
-
body << "#{' ' * (groups.length-index-1)}end"
|
339
|
-
end
|
340
|
-
|
341
|
-
# Indent body and return.
|
342
|
-
body.map! {|line| " " + line}
|
343
|
-
return header + body.join("\n") + "\n" + footer
|
344
|
-
end
|
345
|
-
|
346
|
-
|
347
|
-
####################################
|
348
|
-
# Serialization
|
349
|
-
####################################
|
350
|
-
|
351
|
-
# Serializes the selection object into a JSON string.
|
352
|
-
def to_json(*a); to_hash.to_json(*a); end
|
353
|
-
|
354
|
-
# Serializes the selection object into a hash.
|
355
|
-
def to_hash(*a)
|
356
|
-
{
|
357
|
-
'fields' => fields.to_a.map {|f| f.to_hash},
|
358
|
-
'groups' => groups.to_a.map {|g| g.to_hash},
|
359
|
-
'conditions' => conditions.to_a.map {|c| c.to_hash}
|
360
|
-
}
|
361
|
-
end
|
362
|
-
|
363
|
-
# Deserializes the selection object from a hash.
|
364
|
-
def from_hash(hash, *a)
|
365
|
-
return nil if hash.nil?
|
366
|
-
self.fields = hash['fields'].to_a.map {|h| SkyDB::Query::SelectionField.new.from_hash(h, *a)}
|
367
|
-
self.groups = hash['groups'].to_a.map {|h| SkyDB::Query::SelectionGroup.new.from_hash(h, *a)}
|
368
|
-
self.conditions = hash['conditions'].to_a.map do |h|
|
369
|
-
if h['type'] == 'on'
|
370
|
-
SkyDB::Query::OnCondition.new.from_hash(h, *a)
|
371
|
-
else
|
372
|
-
SkyDB::Query::AfterCondition.new.from_hash(h, *a)
|
373
|
-
end
|
374
|
-
end
|
375
|
-
return self
|
376
|
-
end
|
377
|
-
|
378
|
-
|
379
|
-
####################################
|
380
|
-
# Identifier Management
|
381
|
-
####################################
|
382
|
-
|
383
|
-
# Retrieves a list of all action objects.
|
384
|
-
def get_identifiers
|
385
|
-
actions = []
|
386
|
-
|
387
|
-
conditions.each do |condition|
|
388
|
-
if condition.action.is_a?(SkyDB::Action) && condition.action.id.to_i == 0
|
389
|
-
actions << condition.action
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
return actions
|
394
|
-
end
|
395
|
-
end
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|