skydb 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/sky +85 -0
- data/lib/ext/hash.rb +11 -0
- data/lib/ext/treetop.rb +19 -0
- data/lib/skydb.rb +10 -3
- data/lib/skydb/client.rb +92 -28
- data/lib/skydb/import.rb +7 -0
- data/lib/skydb/import/importer.rb +258 -0
- data/lib/skydb/import/transforms/sky.yml +20 -0
- data/lib/skydb/import/transforms/snowplow.yml +1 -0
- data/lib/skydb/import/translator.rb +119 -0
- data/lib/skydb/message.rb +17 -12
- data/lib/skydb/message/create_table.rb +64 -0
- data/lib/skydb/message/delete_table.rb +66 -0
- data/lib/skydb/message/get_table.rb +74 -0
- data/lib/skydb/message/lookup.rb +79 -0
- data/lib/skydb/property.rb +5 -5
- data/lib/skydb/query.rb +198 -0
- data/lib/skydb/query/after.rb +103 -0
- data/lib/skydb/query/ast/selection_field_syntax_node.rb +26 -0
- data/lib/skydb/query/ast/selection_fields_syntax_node.rb +16 -0
- data/lib/skydb/query/ast/selection_group_syntax_node.rb +16 -0
- data/lib/skydb/query/ast/selection_groups_syntax_node.rb +16 -0
- data/lib/skydb/query/selection.rb +268 -0
- data/lib/skydb/query/selection_field.rb +74 -0
- data/lib/skydb/query/selection_fields_grammar.treetop +46 -0
- data/lib/skydb/query/selection_fields_parse_error.rb +30 -0
- data/lib/skydb/query/selection_group.rb +57 -0
- data/lib/skydb/query/selection_groups_grammar.treetop +31 -0
- data/lib/skydb/query/selection_groups_parse_error.rb +30 -0
- data/lib/skydb/query/validation_error.rb +8 -0
- data/lib/skydb/table.rb +69 -0
- data/lib/skydb/version.rb +1 -1
- data/test/import/importer_test.rb +42 -0
- data/test/import/translator_test.rb +88 -0
- data/test/message/add_event_message_test.rb +1 -1
- data/test/message/add_property_message_test.rb +2 -2
- data/test/message/create_table_message_test.rb +34 -0
- data/test/message/delete_table_message_test.rb +34 -0
- data/test/message/get_table_message_test.rb +19 -0
- data/test/message/lookup_message_test.rb +27 -0
- data/test/message_test.rb +1 -1
- data/test/query/after_test.rb +71 -0
- data/test/query/selection_test.rb +273 -0
- data/test/query_test.rb +156 -0
- data/test/test_helper.rb +3 -0
- metadata +129 -3
@@ -0,0 +1,20 @@
|
|
1
|
+
fields:
|
2
|
+
object_id: object_id:int
|
3
|
+
timestamp: timestamp:date
|
4
|
+
|
5
|
+
translate: |
|
6
|
+
input.each_pair do |k, v|
|
7
|
+
m, prefix, field, data_type = *k.match(/^(?:(action|data)\.)?(\w+)(?:\:(\w+))?$/)
|
8
|
+
next unless ["object_id", "timestamp"].index(field).nil?
|
9
|
+
|
10
|
+
output[prefix] ||= {} unless prefix.nil?
|
11
|
+
target = prefix.nil? ? output : output[prefix]
|
12
|
+
|
13
|
+
target[field] = case data_type.to_s.downcase
|
14
|
+
when "int" then v.to_i
|
15
|
+
when "float" then v.to_f
|
16
|
+
when "boolean" then (v.downcase == "true" || v.downcase == "yes" || v.downcase == "y")
|
17
|
+
when "date" then Chronic.parse(v)
|
18
|
+
else v.to_s
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
fields:
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'chronic'
|
2
|
+
|
3
|
+
class SkyDB
|
4
|
+
class Import
|
5
|
+
class Translator
|
6
|
+
##########################################################################
|
7
|
+
#
|
8
|
+
# Constructor
|
9
|
+
#
|
10
|
+
##########################################################################
|
11
|
+
|
12
|
+
# Initializes the translator.
|
13
|
+
def initialize(options={})
|
14
|
+
self.input_field = options[:input_field]
|
15
|
+
self.output_field = options[:output_field]
|
16
|
+
self.format = options[:format]
|
17
|
+
self.translate_function = options[:translate_function]
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
##########################################################################
|
22
|
+
#
|
23
|
+
# Attributes
|
24
|
+
#
|
25
|
+
##########################################################################
|
26
|
+
|
27
|
+
# The name of the input field to read from.
|
28
|
+
attr_accessor :input_field
|
29
|
+
|
30
|
+
# The name of the output field to write to.
|
31
|
+
attr_accessor :output_field
|
32
|
+
|
33
|
+
# The format of the field (String, Integer, Float, Date).
|
34
|
+
attr_reader :format
|
35
|
+
|
36
|
+
def format=(value)
|
37
|
+
value = 'string' if value.nil?
|
38
|
+
value = 'int' if value == 'integer'
|
39
|
+
@format = value.to_s.downcase
|
40
|
+
end
|
41
|
+
|
42
|
+
# The translation function to execute. This can be a Proc or it can be
|
43
|
+
# a String that is evaluated into a proc with "input" and "output"
|
44
|
+
# arguments.
|
45
|
+
attr_reader :translate_function
|
46
|
+
|
47
|
+
def translate_function=(value)
|
48
|
+
# Only allow nils, procs & strings.
|
49
|
+
if !value.nil? && !value.is_a?(Proc) && !value.is_a?(String)
|
50
|
+
raise "Unable to convert #{value.class} to a translation function."
|
51
|
+
end
|
52
|
+
|
53
|
+
# If this is a string then eval it into a proc.
|
54
|
+
if value.is_a?(String)
|
55
|
+
# If there's no output field set then it's free form.
|
56
|
+
if output_field.nil?
|
57
|
+
@translate_function = eval("lambda { |input,output| #{value} }")
|
58
|
+
|
59
|
+
# If there is an output field set then make the lamda an assignment.
|
60
|
+
else
|
61
|
+
keys = output_field.is_a?(Array) ? output_field : [output_field]
|
62
|
+
keys.map! {|key| "['" + key.gsub("'", "\\'") + "']"}
|
63
|
+
@translate_function = eval("lambda { |input,output| output#{keys.join('')} = #{value.to_s} }")
|
64
|
+
end
|
65
|
+
|
66
|
+
# If this is a proc or a nil then just pass it through.
|
67
|
+
else
|
68
|
+
@translate_function = value
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
##########################################################################
|
74
|
+
#
|
75
|
+
# Methods
|
76
|
+
#
|
77
|
+
##########################################################################
|
78
|
+
|
79
|
+
# Translate a field from the input hash into a field into the
|
80
|
+
# output hash.
|
81
|
+
#
|
82
|
+
# @param [Hash] the input data.
|
83
|
+
# @param [Hash] the output data.
|
84
|
+
def translate(input, output)
|
85
|
+
# If a translation function is set then use it.
|
86
|
+
if !translate_function.nil?
|
87
|
+
translate_function.call(input, output)
|
88
|
+
|
89
|
+
# If the input field and output field are set then apply them.
|
90
|
+
elsif !input_field.nil? && !output_field.nil?
|
91
|
+
value = input[input_field]
|
92
|
+
|
93
|
+
# Navigate down to nested output hash if necessary.
|
94
|
+
if output_field.is_a?(Array)
|
95
|
+
output_field[0..-2].each do |field|
|
96
|
+
output[field] = {} unless output.has_key?(field)
|
97
|
+
output = output[field]
|
98
|
+
end
|
99
|
+
|
100
|
+
output_field = self.output_field.last
|
101
|
+
else
|
102
|
+
output_field = self.output_field
|
103
|
+
end
|
104
|
+
|
105
|
+
# Convert type.
|
106
|
+
output[output_field] = case format
|
107
|
+
when "int" then value.to_i
|
108
|
+
when "float" then value.to_f
|
109
|
+
when "boolean" then (value.downcase == "true" || value.downcase == "yes" || value.downcase == "y")
|
110
|
+
when "date" then Chronic.parse(value)
|
111
|
+
else value.to_s
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
return nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/skydb/message.rb
CHANGED
@@ -18,9 +18,9 @@ class SkyDB
|
|
18
18
|
##########################################################################
|
19
19
|
|
20
20
|
# Initializes the message.
|
21
|
-
def initialize(
|
22
|
-
@
|
23
|
-
@
|
21
|
+
def initialize(message_name)
|
22
|
+
@message_name = message_name
|
23
|
+
@table_name = ""
|
24
24
|
end
|
25
25
|
|
26
26
|
|
@@ -35,18 +35,18 @@ class SkyDB
|
|
35
35
|
####################################
|
36
36
|
|
37
37
|
# The name of message being sent. This is defined by the subclass.
|
38
|
-
attr_reader :
|
38
|
+
attr_reader :message_name
|
39
39
|
|
40
40
|
|
41
41
|
####################################
|
42
|
-
# Table
|
42
|
+
# Table Name
|
43
43
|
####################################
|
44
44
|
|
45
45
|
# The name of the table the message is being sent to/from.
|
46
|
-
attr_accessor :
|
46
|
+
attr_accessor :table_name
|
47
47
|
|
48
|
-
def
|
49
|
-
@
|
48
|
+
def table_name=(value)
|
49
|
+
@table_name = value.to_s
|
50
50
|
end
|
51
51
|
|
52
52
|
|
@@ -68,8 +68,8 @@ class SkyDB
|
|
68
68
|
# Validates that the message is ready to be sent. If any validation issues
|
69
69
|
# are found then an error is raised.
|
70
70
|
def validate!
|
71
|
-
if require_table? && (
|
72
|
-
raise SkyDB::TableRequiredError.new('Table required')
|
71
|
+
if require_table? && (table_name.nil? || table_name.empty?)
|
72
|
+
raise SkyDB::TableRequiredError.new('Table name required')
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -97,8 +97,8 @@ class SkyDB
|
|
97
97
|
def encode_header(buffer)
|
98
98
|
buffer << [
|
99
99
|
SkyDB::Message::VERSION,
|
100
|
-
|
101
|
-
|
100
|
+
message_name,
|
101
|
+
table_name
|
102
102
|
].to_msgpack
|
103
103
|
end
|
104
104
|
|
@@ -123,6 +123,10 @@ class SkyDB
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
require 'skydb/message/create_table'
|
127
|
+
require 'skydb/message/delete_table'
|
128
|
+
require 'skydb/message/get_table'
|
129
|
+
|
126
130
|
require 'skydb/message/add_action'
|
127
131
|
require 'skydb/message/get_action'
|
128
132
|
require 'skydb/message/get_actions'
|
@@ -137,4 +141,5 @@ require 'skydb/message/next_actions'
|
|
137
141
|
require 'skydb/message/lua/aggregate'
|
138
142
|
|
139
143
|
require 'skydb/message/ping'
|
144
|
+
require 'skydb/message/lookup'
|
140
145
|
require 'skydb/message/multi'
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class SkyDB
|
2
|
+
class Message
|
3
|
+
class CreateTable < SkyDB::Message
|
4
|
+
########################################################################
|
5
|
+
#
|
6
|
+
# Constructor
|
7
|
+
#
|
8
|
+
########################################################################
|
9
|
+
|
10
|
+
# Initializes the 'create table' message.
|
11
|
+
#
|
12
|
+
# @param [Table] table the table to create.
|
13
|
+
def initialize(table=nil, options={})
|
14
|
+
super('create_table')
|
15
|
+
self.table = table
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
##########################################################################
|
20
|
+
#
|
21
|
+
# Attributes
|
22
|
+
#
|
23
|
+
##########################################################################
|
24
|
+
|
25
|
+
##################################
|
26
|
+
# Table
|
27
|
+
##################################
|
28
|
+
|
29
|
+
# The talbe to add.
|
30
|
+
attr_reader :table
|
31
|
+
|
32
|
+
def table=(value)
|
33
|
+
@table = value.is_a?(Table) ? value : nil
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
##########################################################################
|
38
|
+
#
|
39
|
+
# Methods
|
40
|
+
#
|
41
|
+
##########################################################################
|
42
|
+
|
43
|
+
##################################
|
44
|
+
# Validation
|
45
|
+
##################################
|
46
|
+
|
47
|
+
# A flag stating if the table is required for this type of message.
|
48
|
+
def require_table?
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
|
52
|
+
####################################
|
53
|
+
# Encoding
|
54
|
+
####################################
|
55
|
+
|
56
|
+
# Encodes the message body.
|
57
|
+
#
|
58
|
+
# @param [IO] buffer the buffer to write the header to.
|
59
|
+
def encode_body(buffer)
|
60
|
+
buffer << table.to_msgpack
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
class SkyDB
|
2
|
+
class Message
|
3
|
+
class DeleteTable < SkyDB::Message
|
4
|
+
########################################################################
|
5
|
+
#
|
6
|
+
# Constructor
|
7
|
+
#
|
8
|
+
########################################################################
|
9
|
+
|
10
|
+
# Initializes the 'delete table' message.
|
11
|
+
#
|
12
|
+
# @param [Table] table the table to delete.
|
13
|
+
def initialize(table=nil, options={})
|
14
|
+
super('delete_table')
|
15
|
+
self.table = table
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
##########################################################################
|
20
|
+
#
|
21
|
+
# Attributes
|
22
|
+
#
|
23
|
+
##########################################################################
|
24
|
+
|
25
|
+
##################################
|
26
|
+
# Table
|
27
|
+
##################################
|
28
|
+
|
29
|
+
# The talbe to add.
|
30
|
+
attr_reader :table
|
31
|
+
|
32
|
+
def table=(value)
|
33
|
+
@table = value.is_a?(Table) ? value : nil
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
##########################################################################
|
38
|
+
#
|
39
|
+
# Methods
|
40
|
+
#
|
41
|
+
##########################################################################
|
42
|
+
|
43
|
+
##################################
|
44
|
+
# Validation
|
45
|
+
##################################
|
46
|
+
|
47
|
+
# A flag stating if the table is required for this type of message.
|
48
|
+
def require_table?
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
|
52
|
+
####################################
|
53
|
+
# Encoding
|
54
|
+
####################################
|
55
|
+
|
56
|
+
# Encodes the message body.
|
57
|
+
#
|
58
|
+
# @param [IO] buffer the buffer to write the header to.
|
59
|
+
def encode_body(buffer)
|
60
|
+
buffer << {
|
61
|
+
name: table.name
|
62
|
+
}.to_msgpack
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class SkyDB
|
2
|
+
class Message
|
3
|
+
class GetTable < SkyDB::Message
|
4
|
+
########################################################################
|
5
|
+
#
|
6
|
+
# Constructor
|
7
|
+
#
|
8
|
+
########################################################################
|
9
|
+
|
10
|
+
# Initializes the 'get_table' message.
|
11
|
+
#
|
12
|
+
# @param [Fixnum] name the name of the table to retrieve.
|
13
|
+
def initialize(name=nil, options={})
|
14
|
+
super('get_table')
|
15
|
+
self.name = name
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
##########################################################################
|
20
|
+
#
|
21
|
+
# Attributes
|
22
|
+
#
|
23
|
+
##########################################################################
|
24
|
+
|
25
|
+
##################################
|
26
|
+
# Name
|
27
|
+
##################################
|
28
|
+
|
29
|
+
# The name of the table to retrieve.
|
30
|
+
attr_reader :name
|
31
|
+
|
32
|
+
def name=(value)
|
33
|
+
@name = value.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
##########################################################################
|
38
|
+
#
|
39
|
+
# Methods
|
40
|
+
#
|
41
|
+
##########################################################################
|
42
|
+
|
43
|
+
##################################
|
44
|
+
# Validation
|
45
|
+
##################################
|
46
|
+
|
47
|
+
# A flag stating if the table is required for this type of message.
|
48
|
+
def require_table?
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
|
52
|
+
####################################
|
53
|
+
# Encoding
|
54
|
+
####################################
|
55
|
+
|
56
|
+
# Encodes the message body.
|
57
|
+
#
|
58
|
+
# @param [IO] buffer the buffer to write the header to.
|
59
|
+
def encode_body(buffer)
|
60
|
+
buffer << {
|
61
|
+
name: name
|
62
|
+
}.to_msgpack
|
63
|
+
end
|
64
|
+
|
65
|
+
def process_response(response)
|
66
|
+
if !response.nil? && !response['table'].nil?
|
67
|
+
response = SkyDB::Table.new(response['table']['name'])
|
68
|
+
else
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class SkyDB
|
2
|
+
class Message
|
3
|
+
class Lookup < SkyDB::Message
|
4
|
+
########################################################################
|
5
|
+
#
|
6
|
+
# Constructor
|
7
|
+
#
|
8
|
+
########################################################################
|
9
|
+
|
10
|
+
# Initializes the 'lookup' message.
|
11
|
+
def initialize(options={})
|
12
|
+
super('lookup')
|
13
|
+
self.actions = options[:actions] || []
|
14
|
+
self.properties = options[:properties] || []
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
##########################################################################
|
19
|
+
#
|
20
|
+
# Attributes
|
21
|
+
#
|
22
|
+
##########################################################################
|
23
|
+
|
24
|
+
##################################
|
25
|
+
# Actions
|
26
|
+
##################################
|
27
|
+
|
28
|
+
# A list of actions to lookup.
|
29
|
+
attr_accessor :actions
|
30
|
+
|
31
|
+
# A list of properties to lookup.
|
32
|
+
attr_accessor :properties
|
33
|
+
|
34
|
+
|
35
|
+
##########################################################################
|
36
|
+
#
|
37
|
+
# Methods
|
38
|
+
#
|
39
|
+
##########################################################################
|
40
|
+
|
41
|
+
####################################
|
42
|
+
# Encoding
|
43
|
+
####################################
|
44
|
+
|
45
|
+
# Encodes the message body.
|
46
|
+
#
|
47
|
+
# @param [IO] buffer the buffer to write the header to.
|
48
|
+
def encode_body(buffer)
|
49
|
+
buffer << {
|
50
|
+
'actionNames' => actions.map {|action| action.name},
|
51
|
+
'propertyNames' => properties.map {|property| property.name}
|
52
|
+
}.to_msgpack
|
53
|
+
end
|
54
|
+
|
55
|
+
####################################
|
56
|
+
# Response processing
|
57
|
+
####################################
|
58
|
+
|
59
|
+
# Updates the action and property identifiers from the returned data.
|
60
|
+
def process_response(response)
|
61
|
+
# Update actions.
|
62
|
+
actions.each_with_index do |action, index|
|
63
|
+
obj = response['actions'][index]
|
64
|
+
action.id = obj.nil? ? 0 : obj['id']
|
65
|
+
end
|
66
|
+
|
67
|
+
# Update properties.
|
68
|
+
properties.each_with_index do |property, index|
|
69
|
+
obj = response['properties'][index]
|
70
|
+
property.id = obj.nil? ? 0 : obj['id']
|
71
|
+
property.type = obj.nil? ? :object : SkyDB::Property::Type.decode(obj['type'])
|
72
|
+
property.data_type = obj.nil? ? nil : obj['dataType']
|
73
|
+
end
|
74
|
+
|
75
|
+
return response
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|