skydb 0.2.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.
Files changed (37) hide show
  1. data/README.md +4 -0
  2. data/lib/ext/string.rb +11 -0
  3. data/lib/skydb.rb +88 -0
  4. data/lib/skydb/action.rb +57 -0
  5. data/lib/skydb/client.rb +216 -0
  6. data/lib/skydb/event.rb +114 -0
  7. data/lib/skydb/message.rb +134 -0
  8. data/lib/skydb/message/add_action.rb +53 -0
  9. data/lib/skydb/message/add_event.rb +72 -0
  10. data/lib/skydb/message/add_property.rb +55 -0
  11. data/lib/skydb/message/get_action.rb +55 -0
  12. data/lib/skydb/message/get_actions.rb +34 -0
  13. data/lib/skydb/message/get_properties.rb +34 -0
  14. data/lib/skydb/message/get_property.rb +55 -0
  15. data/lib/skydb/message/lua/map_reduce.rb +59 -0
  16. data/lib/skydb/message/multi.rb +57 -0
  17. data/lib/skydb/message/next_actions.rb +55 -0
  18. data/lib/skydb/property.rb +93 -0
  19. data/lib/skydb/property/type.rb +40 -0
  20. data/lib/skydb/timestamp.rb +22 -0
  21. data/lib/skydb/version.rb +3 -0
  22. data/test/client_test.rb +71 -0
  23. data/test/event_test.rb +37 -0
  24. data/test/message/add_action_message_test.rb +34 -0
  25. data/test/message/add_event_message_test.rb +35 -0
  26. data/test/message/add_property_message_test.rb +41 -0
  27. data/test/message/get_action_message_test.rb +34 -0
  28. data/test/message/get_actions_message_test.rb +18 -0
  29. data/test/message/get_properties_message_test.rb +18 -0
  30. data/test/message/get_property_message_test.rb +34 -0
  31. data/test/message/lua_map_reduce_message_test.rb +19 -0
  32. data/test/message/multi_message_test.rb +22 -0
  33. data/test/message/next_action_message_test.rb +34 -0
  34. data/test/message_test.rb +15 -0
  35. data/test/skydb_test.rb +20 -0
  36. data/test/test_helper.rb +12 -0
  37. metadata +166 -0
@@ -0,0 +1,4 @@
1
+ sky.rb
2
+ ======
3
+
4
+ The Ruby client for the Sky database.
@@ -0,0 +1,11 @@
1
+ class String
2
+ def to_hex
3
+ bytes.map do |ch|
4
+ if ch.chr.index(/^[a-z_]$/i)
5
+ ch.chr
6
+ else
7
+ '\x%02x' % ch
8
+ end
9
+ end.join('')
10
+ end
11
+ end
@@ -0,0 +1,88 @@
1
+ require 'date'
2
+ require 'msgpack'
3
+ require 'socket'
4
+
5
+ require 'skydb/action'
6
+ require 'skydb/client'
7
+ require 'skydb/event'
8
+ require 'skydb/message'
9
+ require 'skydb/property'
10
+ require 'skydb/timestamp'
11
+ require 'skydb/version'
12
+
13
+ require 'ext/string'
14
+
15
+ class SkyDB
16
+ ############################################################################
17
+ #
18
+ # Errors
19
+ #
20
+ ############################################################################
21
+
22
+ class TableRequiredError < StandardError; end
23
+
24
+ class ObjectIdRequiredError < StandardError; end
25
+ class TimestampRequiredError < StandardError; end
26
+
27
+ ############################################################################
28
+ #
29
+ # Constants
30
+ #
31
+ ############################################################################
32
+
33
+ CLIENT_PASSTHROUGH = [
34
+ :host, :host=, :port, :port=,
35
+ :table, :table=,
36
+ :multi,
37
+ :add_event,
38
+ :add_action, :get_action, :get_actions,
39
+ :add_property, :get_property, :get_properties,
40
+ :next_actions,
41
+ :map_reduce
42
+ ]
43
+
44
+
45
+ ############################################################################
46
+ #
47
+ # Static Attributes
48
+ #
49
+ ############################################################################
50
+
51
+ ######################################
52
+ # Debugging
53
+ ######################################
54
+
55
+ class << self
56
+ attr_accessor :debug
57
+ end
58
+
59
+ ######################################
60
+ # Default Client
61
+ ######################################
62
+
63
+ # The default Sky client.
64
+ def self.client
65
+ @client ||= SkyDB::Client.new()
66
+ return @client
67
+ end
68
+
69
+ def self.client=(value)
70
+ @client = value
71
+ end
72
+
73
+
74
+ ############################################################################
75
+ #
76
+ # Static Methods
77
+ #
78
+ ############################################################################
79
+
80
+ def self.method_missing(method, *args, &block)
81
+ method = method
82
+ if CLIENT_PASSTHROUGH.include?(method.to_sym)
83
+ client.__send__(method.to_sym, *args, &block)
84
+ else
85
+ raise NoMethodError.new("Message type not available: #{method}")
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,57 @@
1
+ class SkyDB
2
+ class Action
3
+ ##########################################################################
4
+ #
5
+ # Constructor
6
+ #
7
+ ##########################################################################
8
+
9
+ # Initializes the action.
10
+ def initialize(options={})
11
+ self.id = options[:id]
12
+ self.name = options[:name]
13
+ end
14
+
15
+
16
+ ##########################################################################
17
+ #
18
+ # Attributes
19
+ #
20
+ ##########################################################################
21
+
22
+ ##################################
23
+ # ID
24
+ ##################################
25
+
26
+ # The action identifier.
27
+ attr_reader :id
28
+
29
+ def id=(value)
30
+ @id = value.to_i
31
+ end
32
+
33
+
34
+ ##################################
35
+ # Name
36
+ ##################################
37
+
38
+ # The name of the action.
39
+ attr_reader :name
40
+
41
+ def name=(value)
42
+ @name = value.to_s
43
+ end
44
+
45
+
46
+ ##########################################################################
47
+ #
48
+ # Methods
49
+ #
50
+ ##########################################################################
51
+
52
+ # Encodes the action into MsgPack format.
53
+ def to_msgpack
54
+ return {id:id, name:name}.to_msgpack
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,216 @@
1
+ class SkyDB
2
+ class Client
3
+ ##########################################################################
4
+ #
5
+ # Constants
6
+ #
7
+ ##########################################################################
8
+
9
+ # The default host to connect to if one is not specified.
10
+ DEFAULT_HOST = 'localhost'
11
+
12
+ # The default port to connect to if one is not specified.
13
+ DEFAULT_PORT = 8585
14
+
15
+
16
+ ##########################################################################
17
+ #
18
+ # Constructor
19
+ #
20
+ ##########################################################################
21
+
22
+ # Initializes the client.
23
+ def initialize(options={})
24
+ self.host = options[:host] || DEFAULT_HOST
25
+ self.port = options[:port] || DEFAULT_PORT
26
+ end
27
+
28
+
29
+ ##########################################################################
30
+ #
31
+ # Attributes
32
+ #
33
+ ##########################################################################
34
+
35
+ # The name of the host to conect to.
36
+ attr_accessor :host
37
+
38
+ # The port on the host to connect to.
39
+ attr_accessor :port
40
+
41
+ # The table to connect to.
42
+ attr_accessor :table
43
+
44
+
45
+ ##########################################################################
46
+ #
47
+ # Methods
48
+ #
49
+ ##########################################################################
50
+
51
+ ####################################
52
+ # Action Messages
53
+ ####################################
54
+
55
+ # Adds an action to the server.
56
+ #
57
+ # @param [Action] action the action to add.
58
+ def add_action(action, options={})
59
+ return send_message(SkyDB::Message::AddAction.new(action, options))
60
+ end
61
+
62
+ # Retrieves an individual action from the server.
63
+ #
64
+ # @param [Fixnum] action_id the identifier of the action to retrieve.
65
+ def get_action(action_id, options={})
66
+ return send_message(SkyDB::Message::GetAction.new(action_id, options))
67
+ end
68
+
69
+ # Retrieves a list of all actions from the server.
70
+ def get_actions(options={})
71
+ return send_message(SkyDB::Message::GetActions.new(options))
72
+ end
73
+
74
+
75
+ ####################################
76
+ # Property Messages
77
+ ####################################
78
+
79
+ # Adds a property to the server.
80
+ #
81
+ # @param [Property] property the property to add.
82
+ def add_property(property, options={})
83
+ return send_message(SkyDB::Message::AddProperty.new(property, options))
84
+ end
85
+
86
+ # Retrieves an individual property from the server.
87
+ #
88
+ # @param [Fixnum] property_id the identifier of the property to retrieve.
89
+ def get_property(property_id, options={})
90
+ return send_message(SkyDB::Message::GetProperty.new(property_id, options))
91
+ end
92
+
93
+ # Retrieves a list of all properties from the server.
94
+ def get_properties(options={})
95
+ return send_message(SkyDB::Message::GetProperties.new(options))
96
+ end
97
+
98
+
99
+ ####################################
100
+ # Event Messages
101
+ ####################################
102
+
103
+ # Adds an event to the server.
104
+ #
105
+ # @param [Event] event the event to add.
106
+ def add_event(event, options={})
107
+ return send_message(SkyDB::Message::AddEvent.new(event, options))
108
+ end
109
+
110
+
111
+ ####################################
112
+ # Path Messages
113
+ ####################################
114
+
115
+ # Finds a count of the action that occurs immediately after a set of
116
+ # actions.
117
+ #
118
+ # @param [Array] prior_action_ids the prior action ids to match on.
119
+ def next_actions(prior_action_ids, options={})
120
+ return send_message(SkyDB::Message::NextActions.new(prior_action_ids, options))
121
+ end
122
+
123
+
124
+ ####################################
125
+ # Lua Messages
126
+ ####################################
127
+
128
+ # Executes a Lua map/reduce job on the server and returns the results.
129
+ #
130
+ # @param [String] source the Lua source code to execute
131
+ def map_reduce(source, options={})
132
+ return send_message(SkyDB::Message::Lua::MapReduce.new(source, options))
133
+ end
134
+
135
+
136
+ ####################################
137
+ # Multi message
138
+ ####################################
139
+
140
+ # Executes multiple messages in one call.
141
+ def multi(options={})
142
+ raise "Already in a multi-message block" unless @multi_message.nil?
143
+
144
+ # Create multi-message.
145
+ @multi_message = SkyDB::Message::Multi.new(options)
146
+
147
+ # Execute the block normally and send the message.
148
+ begin
149
+ yield
150
+
151
+ # Clear multi message so it doesn't add to itself.
152
+ tmp = @multi_message
153
+ @multi_message = nil
154
+
155
+ # Send all messages at once.
156
+ send_message(tmp)
157
+
158
+ ensure
159
+ @multi_message = nil
160
+ end
161
+
162
+ return nil
163
+ end
164
+
165
+
166
+ ####################################
167
+ # Send
168
+ ####################################
169
+
170
+ # Sends a message to the server.
171
+ #
172
+ # @param [SkyDB::Message] message the message to send.
173
+ # @return [Object] the object returned by the server.
174
+ def send_message(message)
175
+ # Set the table if they're not set.
176
+ message.table = table if message.table.nil? || message.table.empty?
177
+
178
+ # Validate message before sending.
179
+ message.validate!
180
+
181
+ # If this is part of a multi message then simply append the message for
182
+ # later sending.
183
+ if !@multi_message.nil?
184
+ @multi_message.messages << message
185
+ return nil
186
+
187
+ # Otherwise send the message immediately.
188
+ else
189
+ # Connect to the server.
190
+ socket = TCPSocket.new(host, port.to_i)
191
+
192
+ # Encode and send message request.
193
+ message.encode(socket)
194
+
195
+ # Decode msgpack response. There should only be one return object.
196
+ response = nil
197
+ unpacker = MessagePack::Unpacker.new(socket)
198
+ unpacker.each do |obj|
199
+ response = obj
200
+ break
201
+ end
202
+
203
+ # Close socket.
204
+ socket.close()
205
+
206
+ # TODO: Exception processing.
207
+
208
+ # Process response back through the message.
209
+ response = message.process_response(response)
210
+
211
+ # Return response.
212
+ return response
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,114 @@
1
+ class SkyDB
2
+ class Event
3
+ ##########################################################################
4
+ #
5
+ # Constructor
6
+ #
7
+ ##########################################################################
8
+
9
+ # Initializes an event object.
10
+ def initialize(options={})
11
+ self.object_id = options[:object_id]
12
+ self.timestamp = options[:timestamp]
13
+ self.action = options[:action]
14
+ self.data = options[:data]
15
+ end
16
+
17
+
18
+ ##########################################################################
19
+ #
20
+ # Attributes
21
+ #
22
+ ##########################################################################
23
+
24
+ ##################################
25
+ # Object ID
26
+ ##################################
27
+
28
+ # The numeric identifier of the object that the event is attached to.
29
+ attr_reader :object_id
30
+
31
+ def object_id=(value)
32
+ @object_id = value.to_i
33
+ end
34
+
35
+ ##################################
36
+ # Timestamp
37
+ ##################################
38
+
39
+ # The timestamp of when the event occurred.
40
+ attr_reader :timestamp
41
+
42
+ def timestamp=(value)
43
+ @timestamp = value.to_time if value.class.method_defined?(:to_time)
44
+ end
45
+
46
+ ##################################
47
+ # Action
48
+ ##################################
49
+
50
+ # The hash containing action related information (including the name of
51
+ # the action being performed).
52
+ attr_reader :action
53
+
54
+ def action=(value)
55
+ clone = {}
56
+
57
+ # Copy over keys
58
+ if !value.nil?
59
+ value.each_pair do |k, v|
60
+ # Only copy keys with valid value types.
61
+ if v.is_a?(String) || v.is_a?(Fixnum) || v.is_a?(Float) || v == true || v == false
62
+ clone[k] = value[k]
63
+ end
64
+ end
65
+ end
66
+
67
+ # Only set the data if we have keys.
68
+ @action = clone.keys.length > 0 ? clone : nil
69
+ end
70
+
71
+ ##################################
72
+ # Data
73
+ ##################################
74
+
75
+ # A hash of data properties to set on the event. Properties can only be
76
+ # a String, Fixnum, Float or Boolean.
77
+ attr_reader :data
78
+
79
+ def data=(value)
80
+ clone = {}
81
+
82
+ # Copy over keys
83
+ if !value.nil?
84
+ value.each_pair do |k, v|
85
+ # Only copy keys with valid value types.
86
+ if v.is_a?(String) || v.is_a?(Fixnum) || v.is_a?(Float) || v == true || v == false
87
+ clone[k] = value[k]
88
+ end
89
+ end
90
+ end
91
+
92
+ # Only set the data if we have keys.
93
+ @data = clone.keys.length > 0 ? clone : nil
94
+ end
95
+
96
+
97
+ ##########################################################################
98
+ #
99
+ # Methods
100
+ #
101
+ ##########################################################################
102
+
103
+ # Encodes the event into MsgPack format.
104
+ def to_msgpack
105
+ obj = {
106
+ :objectId => object_id,
107
+ :timestamp => SkyDB::Timestamp.to_timestamp(timestamp)
108
+ }
109
+ obj[:action] = action unless action.nil? || action.empty?
110
+ obj[:data] = data unless data.nil? || data.empty?
111
+ return obj.to_msgpack
112
+ end
113
+ end
114
+ end