skydb 0.2.2 → 0.2.3
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.
- data/bin/sky +4 -0
- data/lib/skydb.rb +3 -2
- data/lib/skydb/action.rb +19 -0
- data/lib/skydb/client.rb +15 -5
- data/lib/skydb/event.rb +3 -7
- data/lib/skydb/import/importer.rb +236 -59
- data/lib/skydb/import/transforms/apache.yml +4 -0
- data/lib/skydb/import/transforms/sky.yml +20 -12
- data/lib/skydb/message.rb +1 -0
- data/lib/skydb/message/add_event.rb +1 -1
- data/lib/skydb/message/get_actions.rb +4 -0
- data/lib/skydb/message/get_properties.rb +4 -0
- data/lib/skydb/message/get_tables.rb +43 -0
- data/lib/skydb/message/lua/aggregate.rb +4 -0
- data/lib/skydb/property.rb +10 -0
- data/lib/skydb/query.rb +44 -59
- data/lib/skydb/query/after_condition.rb +104 -0
- data/lib/skydb/query/{after.rb → condition.rb} +37 -27
- data/lib/skydb/query/on_condition.rb +53 -0
- data/lib/skydb/query/selection.rb +131 -1
- data/lib/skydb/query/selection_field.rb +25 -0
- data/lib/skydb/query/selection_group.rb +21 -0
- data/lib/skydb/table.rb +7 -0
- data/lib/skydb/version.rb +1 -1
- data/test/integration/query_test.rb +102 -0
- data/test/test_helper.rb +42 -1
- data/test/{client_test.rb → unit/client_test.rb} +0 -0
- data/test/{event_test.rb → unit/event_test.rb} +0 -5
- data/test/unit/import/importer_test.rb +208 -0
- data/test/{import → unit/import}/translator_test.rb +0 -0
- data/test/{message → unit/message}/add_action_message_test.rb +0 -0
- data/test/{message → unit/message}/add_event_message_test.rb +2 -2
- data/test/{message → unit/message}/add_property_message_test.rb +0 -0
- data/test/{message → unit/message}/create_table_message_test.rb +0 -0
- data/test/{message → unit/message}/delete_table_message_test.rb +0 -0
- data/test/{message → unit/message}/get_action_message_test.rb +0 -0
- data/test/{message → unit/message}/get_actions_message_test.rb +0 -0
- data/test/{message → unit/message}/get_properties_message_test.rb +0 -0
- data/test/{message → unit/message}/get_property_message_test.rb +0 -0
- data/test/{message → unit/message}/get_table_message_test.rb +0 -0
- data/test/unit/message/get_tables_message_test.rb +18 -0
- data/test/{message → unit/message}/lookup_message_test.rb +0 -0
- data/test/{message → unit/message}/lua_aggregate_message_test.rb +0 -0
- data/test/{message → unit/message}/multi_message_test.rb +0 -0
- data/test/{message → unit/message}/next_action_message_test.rb +0 -0
- data/test/{message → unit/message}/ping_message_test.rb +0 -0
- data/test/{message_test.rb → unit/message_test.rb} +0 -0
- data/test/unit/query/after_test.rb +89 -0
- data/test/{query/after_test.rb → unit/query/on_test.rb} +10 -10
- data/test/{query → unit/query}/selection_test.rb +2 -2
- data/test/{query_test.rb → unit/query_test.rb} +32 -6
- data/test/{skydb_test.rb → unit/skydb_test.rb} +0 -0
- metadata +165 -53
- data/test/import/importer_test.rb +0 -42
@@ -1,20 +1,28 @@
|
|
1
1
|
fields:
|
2
|
-
object_id: object_id
|
2
|
+
object_id: object_id
|
3
3
|
timestamp: timestamp:date
|
4
4
|
|
5
5
|
translate: |
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
def process(_input, _output)
|
7
|
+
_input.each_pair do |k, v|
|
8
|
+
if v.is_a?(Hash)
|
9
|
+
_output[k] = {}
|
10
|
+
process(v, _output[k])
|
11
|
+
else
|
12
|
+
m, prefix, field, data_type = *k.match(/^(?:(action|data)\.)?(\w+)(?:\:(\w+))?$/)
|
13
|
+
next unless ["object_id", "timestamp"].index(field).nil?
|
9
14
|
|
10
|
-
|
11
|
-
|
15
|
+
_output[prefix] ||= {} unless prefix.nil?
|
16
|
+
target = prefix.nil? ? _output : _output[prefix]
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
target[field] = case data_type.to_s.downcase
|
19
|
+
when "int" then v.to_i
|
20
|
+
when "float" then v.to_f
|
21
|
+
when "boolean" then (v.downcase == "true" || v.downcase == "yes" || v.downcase == "y")
|
22
|
+
when "date" then Chronic.parse(v)
|
23
|
+
else v.to_s
|
24
|
+
end
|
25
|
+
end
|
19
26
|
end
|
20
27
|
end
|
28
|
+
process(input, output)
|
data/lib/skydb/message.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
class SkyDB
|
2
|
+
class Message
|
3
|
+
class GetTables < SkyDB::Message
|
4
|
+
########################################################################
|
5
|
+
#
|
6
|
+
# Constructor
|
7
|
+
#
|
8
|
+
########################################################################
|
9
|
+
|
10
|
+
# Initializes the 'get_tables' message.
|
11
|
+
def initialize(options={})
|
12
|
+
super('get_tables')
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
##########################################################################
|
17
|
+
#
|
18
|
+
# Methods
|
19
|
+
#
|
20
|
+
##########################################################################
|
21
|
+
|
22
|
+
##################################
|
23
|
+
# Validation
|
24
|
+
##################################
|
25
|
+
|
26
|
+
# A flag stating if the table is required for this type of message.
|
27
|
+
def require_table?
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
|
31
|
+
####################################
|
32
|
+
# Encoding
|
33
|
+
####################################
|
34
|
+
|
35
|
+
def process_response(response)
|
36
|
+
tables = []
|
37
|
+
response['tables'].each do |hash|
|
38
|
+
tables << SkyDB::Table.new(hash['name'])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/skydb/property.rb
CHANGED
data/lib/skydb/query.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'skydb/query/selection'
|
2
|
-
require 'skydb/query/
|
2
|
+
require 'skydb/query/condition'
|
3
|
+
require 'skydb/query/after_condition'
|
4
|
+
require 'skydb/query/on_condition'
|
3
5
|
require 'skydb/query/validation_error'
|
4
6
|
|
5
7
|
class SkyDB
|
@@ -17,8 +19,7 @@ class SkyDB
|
|
17
19
|
|
18
20
|
def initialize(options={})
|
19
21
|
self.client = options[:client]
|
20
|
-
self.selection = options[:selection]
|
21
|
-
self.conditions = options[:conditions] || []
|
22
|
+
self.selection = options[:selection]
|
22
23
|
end
|
23
24
|
|
24
25
|
|
@@ -32,10 +33,13 @@ class SkyDB
|
|
32
33
|
attr_accessor :client
|
33
34
|
|
34
35
|
# The properties that should be selected from the database.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
attr_reader :selection
|
37
|
+
|
38
|
+
def selection=(value)
|
39
|
+
@selection = value
|
40
|
+
value.query = self unless value.nil?
|
41
|
+
return value
|
42
|
+
end
|
39
43
|
|
40
44
|
# The number of idle seconds that separates sessions.
|
41
45
|
attr_accessor :session_idle_time
|
@@ -51,34 +55,15 @@ class SkyDB
|
|
51
55
|
# Helpers
|
52
56
|
####################################
|
53
57
|
|
54
|
-
#
|
58
|
+
# Creates and appends a new selection to the query.
|
55
59
|
#
|
56
60
|
# @param [String] fields A list of fields to add to the selection.
|
57
61
|
#
|
58
|
-
# @return [
|
62
|
+
# @return [Selection] The newly created selection object is returned.
|
59
63
|
def select(*fields)
|
64
|
+
self.selection = SkyDB::Query::Selection.new()
|
60
65
|
selection.select(*fields)
|
61
|
-
return
|
62
|
-
end
|
63
|
-
|
64
|
-
# Adds one or more grouping fields to the selection of the query.
|
65
|
-
#
|
66
|
-
# @param [String] groups A list of groups to add to the selection.
|
67
|
-
#
|
68
|
-
# @return [Query] The query object is returned.
|
69
|
-
def group_by(*groups)
|
70
|
-
selection.group_by(*groups)
|
71
|
-
return self
|
72
|
-
end
|
73
|
-
|
74
|
-
# Adds an 'after' condition to the query.
|
75
|
-
#
|
76
|
-
# @param [Hash] options The options to pass to the 'after' condition.
|
77
|
-
#
|
78
|
-
# @return [Query] The query object is returned.
|
79
|
-
def after(options={})
|
80
|
-
conditions << SkyDB::Query::After.new(options)
|
81
|
-
return self
|
66
|
+
return selection
|
82
67
|
end
|
83
68
|
|
84
69
|
# Sets the session idle seconds and returns the query object.
|
@@ -133,43 +118,47 @@ class SkyDB
|
|
133
118
|
|
134
119
|
# Generate selection.
|
135
120
|
code = []
|
136
|
-
code << selection.
|
137
|
-
|
138
|
-
# Generate condition functions.
|
139
|
-
conditions.each_with_index do |condition, index|
|
140
|
-
condition.function_name ||= "__condition#{nextseq}"
|
141
|
-
code << condition.codegen
|
142
|
-
end
|
143
|
-
|
144
|
-
# Generate the invocation of the conditions.
|
145
|
-
conditionals = conditions.map {|condition| "#{condition.function_name}(cursor, data)"}.join(' and ')
|
146
|
-
conditionals = "true" if conditions.length == 0
|
121
|
+
code << selection.codegen()
|
147
122
|
|
148
123
|
# Generate aggregate() function.
|
149
124
|
code << "function aggregate(cursor, data)"
|
150
125
|
code << " cursor:set_session_idle(#{session_idle_time.to_i})" if session_idle_time.to_i > 0
|
151
|
-
code << "
|
152
|
-
code << " while cursor:next() do"
|
153
|
-
code << " if #{conditionals} then"
|
154
|
-
code << " select(cursor, data)"
|
155
|
-
code << " end"
|
156
|
-
code << " end"
|
157
|
-
code << " end"
|
126
|
+
code << " select_all(cursor, data)"
|
158
127
|
code << "end"
|
159
128
|
code << ""
|
160
|
-
|
161
|
-
# Generate merge function.
|
162
|
-
code << selection.codegen_merge()
|
163
129
|
|
164
130
|
return code.join("\n")
|
165
131
|
end
|
166
132
|
|
167
133
|
|
168
134
|
####################################
|
169
|
-
#
|
135
|
+
# Serialization
|
170
136
|
####################################
|
171
137
|
|
172
|
-
|
138
|
+
# Serializes the query object into a JSON string.
|
139
|
+
def to_json(*a); to_hash.to_json(*a); end
|
140
|
+
|
141
|
+
# Serializes the query object into a hash.
|
142
|
+
def to_hash(*a)
|
143
|
+
hash = {}
|
144
|
+
hash['selections'] = [selection.to_hash(*a)] unless selection.nil?
|
145
|
+
hash['sessionIdleTime'] = session_idle_time.to_i
|
146
|
+
hash
|
147
|
+
end
|
148
|
+
|
149
|
+
# Deserializes the query object into a hash.
|
150
|
+
def from_hash(hash, *a)
|
151
|
+
return if hash.nil?
|
152
|
+
selection_hash, x = *hash['selections']
|
153
|
+
self.selection = SkyDB::Query::Selection.new.from_hash(selection_hash)
|
154
|
+
self.session_idle_time = hash['sessionIdleTime'].to_i
|
155
|
+
return self
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
####################################
|
160
|
+
# Utility
|
161
|
+
####################################
|
173
162
|
|
174
163
|
# Generates a sequence number used for uniquely naming objects and
|
175
164
|
# functions in the query.
|
@@ -179,13 +168,9 @@ class SkyDB
|
|
179
168
|
|
180
169
|
# Looks up all actions and properties that are missing an identifier.
|
181
170
|
def lookup_identifiers
|
182
|
-
# Find all the actions on
|
171
|
+
# Find all the actions on the selection that are missing an id.
|
183
172
|
actions = []
|
184
|
-
|
185
|
-
if condition.action.is_a?(SkyDB::Action) && condition.action.id.to_i == 0
|
186
|
-
actions << condition.action
|
187
|
-
end
|
188
|
-
end
|
173
|
+
actions.concat(selection.get_identifiers())
|
189
174
|
|
190
175
|
# Lookup all the actions.
|
191
176
|
if actions.length > 0
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class SkyDB
|
2
|
+
class Query
|
3
|
+
# The 'after' condition filters out selection only after the condition
|
4
|
+
# has been fulfilled.
|
5
|
+
class AfterCondition < 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
|
+
self.within = options[:within]
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
##########################################################################
|
20
|
+
#
|
21
|
+
# Attributes
|
22
|
+
#
|
23
|
+
##########################################################################
|
24
|
+
|
25
|
+
attr_accessor :within
|
26
|
+
|
27
|
+
|
28
|
+
##########################################################################
|
29
|
+
#
|
30
|
+
# Methods
|
31
|
+
#
|
32
|
+
##########################################################################
|
33
|
+
|
34
|
+
##################################
|
35
|
+
# Validation
|
36
|
+
##################################
|
37
|
+
|
38
|
+
# Validates that the object is correct before executing a codegen.
|
39
|
+
def validate!
|
40
|
+
# Do not allow the :enter action. That is reserved for the 'On'
|
41
|
+
# condition.
|
42
|
+
if action == :enter
|
43
|
+
raise SkyDB::Query::ValidationError.new("Enter actions cannot be used with an 'after' condition. Please use an 'on' condition instead.")
|
44
|
+
end
|
45
|
+
|
46
|
+
super
|
47
|
+
|
48
|
+
return nil
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
##################################
|
53
|
+
# Codegen
|
54
|
+
##################################
|
55
|
+
|
56
|
+
# Generates Lua code to match a given action.
|
57
|
+
def codegen(options={})
|
58
|
+
header, body, footer = "function #{function_name.to_s}(cursor, data)\n", [], "end\n"
|
59
|
+
within_unit = (within.nil? ? nil : within[:unit])
|
60
|
+
|
61
|
+
# Find the matching event and then move to the next one for selection.
|
62
|
+
body << "if cursor:eos() or cursor:eof() then return false end"
|
63
|
+
body << "remaining = #{within[:quantity].to_i}" if within_unit == 'step'
|
64
|
+
body << "repeat"
|
65
|
+
body << " if remaining <= 0 then return false end" if within_unit == 'step'
|
66
|
+
body << " if cursor.event.action_id == #{action.id.to_i} then"
|
67
|
+
body << " cursor:next()"
|
68
|
+
body << " return true"
|
69
|
+
body << " end"
|
70
|
+
body << " remaining = remaining - 1" if within_unit == 'step'
|
71
|
+
body << "until not cursor:next()"
|
72
|
+
body << "return false"
|
73
|
+
|
74
|
+
# Indent body and return.
|
75
|
+
body.map! {|line| " " + line}
|
76
|
+
return header + body.join("\n") + "\n" + footer
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
####################################
|
81
|
+
# Serialization
|
82
|
+
####################################
|
83
|
+
|
84
|
+
# Serializes the condition into a hash.
|
85
|
+
def to_hash(*a)
|
86
|
+
json = super(*a)
|
87
|
+
json['within'] = within.to_hash(*a) unless within.nil?
|
88
|
+
json
|
89
|
+
end
|
90
|
+
|
91
|
+
# Deserializes the condition from a hash.
|
92
|
+
def from_hash(hash, *a)
|
93
|
+
super(hash, *a)
|
94
|
+
return nil if hash.nil?
|
95
|
+
|
96
|
+
hash['within']._symbolize_keys! unless hash['within'].nil?
|
97
|
+
self.within = hash['within']
|
98
|
+
|
99
|
+
return self
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
@@ -1,16 +1,15 @@
|
|
1
1
|
class SkyDB
|
2
2
|
class Query
|
3
|
-
# The
|
4
|
-
#
|
5
|
-
class
|
3
|
+
# The Condition class is the base class for all query classes that limit
|
4
|
+
# the selection.
|
5
|
+
class Condition
|
6
6
|
##########################################################################
|
7
7
|
#
|
8
8
|
# Constructor
|
9
9
|
#
|
10
10
|
##########################################################################
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
options.merge!(action.is_a?(Hash) ? action : {:action => action})
|
12
|
+
def initialize(options={})
|
14
13
|
self.action = options[:action]
|
15
14
|
self.function_name = options[:function_name]
|
16
15
|
end
|
@@ -30,13 +29,11 @@ class SkyDB
|
|
30
29
|
attr_reader :action
|
31
30
|
|
32
31
|
def action=(value)
|
33
|
-
if value.is_a?(
|
34
|
-
@action = :enter
|
35
|
-
elsif value.is_a?(String)
|
32
|
+
if value.is_a?(String)
|
36
33
|
@action = SkyDB::Action.new(:name => value)
|
37
34
|
elsif value.is_a?(Fixnum)
|
38
35
|
@action = SkyDB::Action.new(:id => value)
|
39
|
-
elsif value.is_a?(SkyDB::Action)
|
36
|
+
elsif value.is_a?(SkyDB::Action) || value == :enter
|
40
37
|
@action = value
|
41
38
|
else
|
42
39
|
@action = nil
|
@@ -57,7 +54,7 @@ class SkyDB
|
|
57
54
|
# Validates that the object is correct before executing a codegen.
|
58
55
|
def validate!
|
59
56
|
# Require the action identifier.
|
60
|
-
if action.nil? || action.id.to_i == 0
|
57
|
+
if action.nil? || action == :enter || action.id.to_i == 0
|
61
58
|
raise SkyDB::Query::ValidationError.new("Action with non-zero identifier required.")
|
62
59
|
end
|
63
60
|
|
@@ -77,25 +74,38 @@ class SkyDB
|
|
77
74
|
|
78
75
|
# Generates Lua code to match a given action.
|
79
76
|
def codegen(options={})
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
94
96
|
end
|
97
|
+
json
|
98
|
+
end
|
95
99
|
|
96
|
-
|
97
|
-
|
98
|
-
return
|
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
|
99
109
|
end
|
100
110
|
end
|
101
111
|
end
|