skydb 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MTYyYTgwMmM5YTIxMzdjNzk0YjhkNTc5ZmQ1NWIyODcwOTkyOGNmZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NjdmZWY1NDMxNGQ3OTJmNzk0MTMxMjIwMWRkMDczYTg1ZDQ0MTZiMA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZjE4MGM3NDJkMDU4ODEzOGYzMzVmZDkwZTVhODNkNDA5NGQzYzRhNjk2YWQ5
|
10
|
+
MDNmZmVjODg3NjdlNmE3MGU2YTE0NWY2ODgwZWE3OGZmMTY4NDY4YTI3OGEx
|
11
|
+
MjVkZGI2YjM0YmZmOTMzM2U3ZmI3NTZiNWUzOWNiYmY0MTQ1MWE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MWI2NTU4ZTRlYzg3ZTI1OWI4MThlYTY1NTdmZWQ4NWFmYjlmZTQxYjJkYzQ0
|
14
|
+
ZGQ3MGM4NGRjNjc1MTlkODMzMzFjNjZiNGU0ZGFmYzYxMjQxMjI4MmE4MjFj
|
15
|
+
YzEwZGQwMDI3ODQyNmJkNzc3MWU4ZTA4MjFlODQ2ZGVhMDk3MTA=
|
data/README.md
CHANGED
@@ -1,4 +1,168 @@
|
|
1
1
|
sky.rb
|
2
2
|
======
|
3
3
|
|
4
|
-
|
4
|
+
## Overview
|
5
|
+
|
6
|
+
The official Ruby client for the [Sky database](http://skydb.io).
|
7
|
+
This client provides a simple wrapper around the Sky HTTP-based API.
|
8
|
+
|
9
|
+
|
10
|
+
## API
|
11
|
+
|
12
|
+
### The Basics
|
13
|
+
|
14
|
+
To connect to your Sky database, simply create a client pointing to the appropriate host and port.
|
15
|
+
The client will default to `localhost:8585` unless otherwise specified.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
require "skydb"
|
19
|
+
client = SkyDB::Client.new(:host => 'localhost', :port => 8585)
|
20
|
+
```
|
21
|
+
|
22
|
+
### Table API
|
23
|
+
|
24
|
+
The table API allows you to retrieve table information, create tables and delete tables.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require "skydb"
|
28
|
+
client = SkyDB::Client.new()
|
29
|
+
|
30
|
+
# Retrieve a list of all tables.
|
31
|
+
tables = client.get_tables()
|
32
|
+
|
33
|
+
# Retrieve data about a single table.
|
34
|
+
table = client.get_table()
|
35
|
+
|
36
|
+
# Create a new table named 'foo'.
|
37
|
+
table = client.create_table(:name => 'foo')
|
38
|
+
|
39
|
+
# Delete the 'foo' table.
|
40
|
+
client.delete_table(table)
|
41
|
+
```
|
42
|
+
|
43
|
+
|
44
|
+
### Property API
|
45
|
+
|
46
|
+
The property API allows you to retrieve property information, create properties, update properties and delete properties from a table.
|
47
|
+
|
48
|
+
There are five data types in Sky: `string`, `integer`, `float`, `boolean` and `factor`.
|
49
|
+
The first four are self-explanatory.
|
50
|
+
The `factor` data type acts like a `string` but internally it is represented as an integer with a lookup to the original string value.
|
51
|
+
This type should be used when you have categorical data such as gender, country or any property that has a limited number of possible values.
|
52
|
+
|
53
|
+
In addition to data types, Sky properties can also be transient or permanent.
|
54
|
+
A transient property means that the value of the property exists only for a single moment in time.
|
55
|
+
Typically this would be used for data related to a specific event such as the purchase amount of a checkout on a web site.
|
56
|
+
A permanent property means that the value of the property stays in effect until changed.
|
57
|
+
An example of this would be a user's gender or their household income.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
require "skydb"
|
61
|
+
client = SkyDB::Client.new()
|
62
|
+
table = client.get_table(:name => 'foo')
|
63
|
+
|
64
|
+
# Retrieve a list of all properties on the table.
|
65
|
+
properties = table.get_properties()
|
66
|
+
|
67
|
+
# Retrieve a single property from the table.
|
68
|
+
property = table.get_property()
|
69
|
+
|
70
|
+
# Create a new transient, integer property named 'purchase_amount'.
|
71
|
+
property = table.create_property(:name => 'purchase_amount', :transient => true, :data_type => 'integer')
|
72
|
+
|
73
|
+
# Update the 'purchase_amount' property to be named 'total_purchase_amount'.
|
74
|
+
# Note that only the name change be changed on a property -- not it's transiency or data type.
|
75
|
+
property.name = 'total_purchase_amount'
|
76
|
+
table.update_property(property)
|
77
|
+
|
78
|
+
# Delete the property.
|
79
|
+
table.delete_property(property)
|
80
|
+
```
|
81
|
+
|
82
|
+
### Event API
|
83
|
+
|
84
|
+
The event API allows you to add events to objects on a table.
|
85
|
+
In Sky, objects are simply a sum of their events so objects do not need to be created explicitly.
|
86
|
+
Simply add events using an object key (e.g. a user id, e-mail address, or some other uniquely identifying string).
|
87
|
+
|
88
|
+
When adding events to the database, Sky will automatically deduplicate permanent values.
|
89
|
+
For example, if you set an object's "gender" property to "male" at Jan 1st 2000 at 1pm and then set it to "male" again on Jan 1st 2000 at 2pm then Sky will remove the second gender value since it can be determined by the first event.
|
90
|
+
|
91
|
+
Sky will also merge a events if adding an event that already exists at the same time for a given object.
|
92
|
+
This is typically unlikely as Sky's time resolution is one microsecond.
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
require "skydb"
|
96
|
+
client = SkyDB::Client.new()
|
97
|
+
table = client.get_table(:name => 'foo')
|
98
|
+
table.create_property(:name => "action", :transient => true, :data_type => "factor")
|
99
|
+
table.create_property(:name => "purchase_amount", :transient => true, :data_type => "float")
|
100
|
+
table.create_property(:name => "full_name", :data_type => "string")
|
101
|
+
|
102
|
+
# Retrieve a list of all events for an object.
|
103
|
+
events = table.get_events("susy")
|
104
|
+
|
105
|
+
# Retrieve the event that occurs at a given moment for an object.
|
106
|
+
event = table.get_event("susy", DateTime.iso8601('2000-01-01T00:00:00Z'))
|
107
|
+
|
108
|
+
# Add a new event for an object (and merge with an existing event).
|
109
|
+
table.add_event("susy", :timestamp => DateTime.iso8601('2000-01-01T00:00:00Z'), :data => {"action" => "checekout", "purchase_amount" => 100, "full_name" => "Susy Que"})
|
110
|
+
|
111
|
+
# Add a new event for an object (and replace an existing event).
|
112
|
+
table.add_event("susy", {:timestamp => DateTime.iso8601('2000-01-01T00:00:00Z'), :data => {"action" => "checekout", "purchase_amount" => 100, "full_name" => "Susy Que"}}, :method => :replace)
|
113
|
+
|
114
|
+
# Delete an event at the given moment.
|
115
|
+
table.delete_event("susy", :timestamp => DateTime.iso8601('2000-01-01T00:00:00Z'))
|
116
|
+
```
|
117
|
+
|
118
|
+
### Query API
|
119
|
+
|
120
|
+
Once your event data is in Sky, you can quickly iterate over it and query it for information.
|
121
|
+
There are two primitives in the Sky query system: conditions & selections.
|
122
|
+
Conditions allow you to execute nested conditions or selections if its expression evaluates to true.
|
123
|
+
Selections allow you to actually retrieve the data from the current event and group it by multiple dimensions.
|
124
|
+
|
125
|
+
For a full explanation of the Sky query system, please visit the [Sky web site](http://skydb.io).
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
require "skydb"
|
129
|
+
client = SkyDB::Client.new()
|
130
|
+
table = client.get_table(:name => 'users')
|
131
|
+
table.create_property(:name => "action", :transient => true, :data_type => "factor")
|
132
|
+
table.create_property(:name => "purchase_amount", :transient => true, :data_type => "float")
|
133
|
+
table.create_property(:name => "gender", :data_type => "factor")
|
134
|
+
table.create_property(:name => "state", :data_type => "factor")
|
135
|
+
|
136
|
+
# Perform a simple count of all events in the table.
|
137
|
+
results = client.query([:type => 'selection', :fields => [{:name => 'myCount', :expression => 'count()'}]])
|
138
|
+
|
139
|
+
# Count the number of users that performed the actions 'view home page', 'sign up' and then 'checkout' within a session
|
140
|
+
# and group the results by gender and state.
|
141
|
+
results = client.query(
|
142
|
+
:sessionIdleTime => 7200,
|
143
|
+
:steps => [
|
144
|
+
{:type => 'condition', :expression => 'action == "view home page"', :steps => [
|
145
|
+
{:type => 'condition', :expression => 'action == "sign up"', :within => [1,1], :steps => [
|
146
|
+
{:type => 'condition', :expression => 'checkout', :within => [1,1], :steps => [
|
147
|
+
{:type => 'selection', :dimensions => ['gender', 'state'], :fields => [
|
148
|
+
{:name => 'count', :expression => 'count()'},
|
149
|
+
{:name => 'total_amount', :expression => 'sum(purchase_amount)'}
|
150
|
+
]},
|
151
|
+
]}
|
152
|
+
]}
|
153
|
+
]}
|
154
|
+
]
|
155
|
+
)
|
156
|
+
#=> {'gender' => {'m' => {'state' => {'CA' => {'count' => 10, 'total_amount' => 291.93}}}}
|
157
|
+
```
|
158
|
+
|
159
|
+
### Utility API
|
160
|
+
|
161
|
+
To check if the server is up and running, you can use the `ping` command:
|
162
|
+
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
require "skydb"
|
166
|
+
client = SkyDB::Client.new()
|
167
|
+
is_running = client.ping()
|
168
|
+
```
|
data/lib/skydb.rb
CHANGED
@@ -1,23 +1,7 @@
|
|
1
1
|
require 'date'
|
2
|
-
require '
|
3
|
-
require 'socket'
|
4
|
-
require 'treetop'
|
2
|
+
require 'net/http'
|
5
3
|
require 'json'
|
6
4
|
|
7
|
-
require 'skydb/action'
|
8
|
-
require 'skydb/client'
|
9
|
-
require 'skydb/event'
|
10
|
-
require 'skydb/message'
|
11
|
-
require 'skydb/property'
|
12
|
-
require 'skydb/query'
|
13
|
-
require 'skydb/table'
|
14
|
-
require 'skydb/timestamp'
|
15
|
-
require 'skydb/version'
|
16
|
-
|
17
|
-
require 'ext/hash'
|
18
|
-
require 'ext/string'
|
19
|
-
require 'ext/treetop'
|
20
|
-
|
21
5
|
class SkyDB
|
22
6
|
############################################################################
|
23
7
|
#
|
@@ -25,31 +9,8 @@ class SkyDB
|
|
25
9
|
#
|
26
10
|
############################################################################
|
27
11
|
|
28
|
-
class
|
29
|
-
|
30
|
-
class ObjectIdRequiredError < StandardError; end
|
31
|
-
class TimestampRequiredError < StandardError; end
|
12
|
+
class SkyError < StandardError; end
|
32
13
|
|
33
|
-
############################################################################
|
34
|
-
#
|
35
|
-
# Constants
|
36
|
-
#
|
37
|
-
############################################################################
|
38
|
-
|
39
|
-
CLIENT_PASSTHROUGH = [
|
40
|
-
:host, :host=, :port, :port=,
|
41
|
-
:table_name, :table_name=,
|
42
|
-
:multi, :ping, :lookup,
|
43
|
-
:add_event,
|
44
|
-
:create_table, :delete_table, :get_table, :get_tables,
|
45
|
-
:add_action, :get_action, :get_actions,
|
46
|
-
:add_property, :get_property, :get_properties,
|
47
|
-
:next_actions,
|
48
|
-
:aggregate,
|
49
|
-
:query, :select
|
50
|
-
]
|
51
|
-
|
52
|
-
|
53
14
|
############################################################################
|
54
15
|
#
|
55
16
|
# Static Attributes
|
@@ -64,20 +25,6 @@ class SkyDB
|
|
64
25
|
attr_accessor :debug
|
65
26
|
end
|
66
27
|
|
67
|
-
######################################
|
68
|
-
# Default Client
|
69
|
-
######################################
|
70
|
-
|
71
|
-
# The default Sky client.
|
72
|
-
def self.client
|
73
|
-
@client ||= SkyDB::Client.new()
|
74
|
-
return @client
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.client=(value)
|
78
|
-
@client = value
|
79
|
-
end
|
80
|
-
|
81
28
|
|
82
29
|
############################################################################
|
83
30
|
#
|
@@ -85,12 +32,22 @@ class SkyDB
|
|
85
32
|
#
|
86
33
|
############################################################################
|
87
34
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
35
|
+
######################################
|
36
|
+
# Timestamps
|
37
|
+
######################################
|
38
|
+
|
39
|
+
# Formats a timestamp as ISO8601 formatted string with fractional seconds.
|
40
|
+
def self.format_timestamp(timestamp)
|
41
|
+
if timestamp.nil?
|
42
|
+
return nil
|
92
43
|
else
|
93
|
-
|
44
|
+
return timestamp.to_time.utc.to_datetime.strftime('%Y-%m-%dT%H:%M:%S.%6NZ')
|
94
45
|
end
|
95
46
|
end
|
96
|
-
end
|
47
|
+
end
|
48
|
+
|
49
|
+
require 'skydb/client'
|
50
|
+
require 'skydb/table'
|
51
|
+
require 'skydb/property'
|
52
|
+
require 'skydb/event'
|
53
|
+
require 'skydb/version'
|
data/lib/skydb/client.rb
CHANGED
@@ -1,5 +1,20 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
1
4
|
class SkyDB
|
2
5
|
class Client
|
6
|
+
##########################################################################
|
7
|
+
#
|
8
|
+
# Errors
|
9
|
+
#
|
10
|
+
##########################################################################
|
11
|
+
|
12
|
+
class ServerError < SkyError
|
13
|
+
attr_accessor :status
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
|
3
18
|
##########################################################################
|
4
19
|
#
|
5
20
|
# Constants
|
@@ -21,8 +36,6 @@ class SkyDB
|
|
21
36
|
|
22
37
|
# Initializes the client.
|
23
38
|
def initialize(options={})
|
24
|
-
@multi_message_max_count = 0
|
25
|
-
|
26
39
|
self.host = options[:host] || DEFAULT_HOST
|
27
40
|
self.port = options[:port] || DEFAULT_PORT
|
28
41
|
end
|
@@ -40,9 +53,6 @@ class SkyDB
|
|
40
53
|
# The port on the host to connect to.
|
41
54
|
attr_accessor :port
|
42
55
|
|
43
|
-
# The name of the table to connect to.
|
44
|
-
attr_accessor :table_name
|
45
|
-
|
46
56
|
|
47
57
|
##########################################################################
|
48
58
|
#
|
@@ -51,256 +61,246 @@ class SkyDB
|
|
51
61
|
##########################################################################
|
52
62
|
|
53
63
|
####################################
|
54
|
-
# Table
|
64
|
+
# Table API
|
55
65
|
####################################
|
56
66
|
|
67
|
+
# Retrieves a list of tables on the server.
|
68
|
+
def get_tables(options={})
|
69
|
+
data = send(:get, "/tables")
|
70
|
+
tables = data.map {|i| Table.new(:client => self).from_hash(i)}
|
71
|
+
return tables
|
72
|
+
end
|
73
|
+
|
74
|
+
# Retrieves a single table from the server.
|
75
|
+
def get_table(name, options={})
|
76
|
+
raise ArgumentError.new("Table name required") if name.nil?
|
77
|
+
data = send(:get, "/tables/#{name}")
|
78
|
+
table = Table.new(:client => self).from_hash(data)
|
79
|
+
return table
|
80
|
+
end
|
81
|
+
|
57
82
|
# Creates a table on the server.
|
58
83
|
#
|
59
|
-
# @param [Table] table the table to
|
84
|
+
# @param [Table] table the table to create.
|
60
85
|
def create_table(table, options={})
|
61
|
-
|
86
|
+
raise ArgumentError.new("Table required") if table.nil?
|
87
|
+
table = Table.new(table) if table.is_a?(Hash)
|
88
|
+
table.client = self
|
89
|
+
data = send(:post, "/tables", table.to_hash)
|
90
|
+
return table.from_hash(data)
|
62
91
|
end
|
63
92
|
|
64
93
|
# Deletes a table on the server.
|
65
94
|
#
|
66
95
|
# @param [Table] table the table to delete.
|
67
96
|
def delete_table(table, options={})
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
#
|
74
|
-
# @param [Fixnum] name the table name to retrieve.
|
75
|
-
def get_table(name, options={})
|
76
|
-
return send_message(SkyDB::Message::GetTable.new(name, options))
|
77
|
-
end
|
78
|
-
|
79
|
-
# Retrieves a list of all tables on the server.
|
80
|
-
def get_tables(options={})
|
81
|
-
return send_message(SkyDB::Message::GetTables.new(options))
|
97
|
+
raise ArgumentError.new("Table required") if table.nil?
|
98
|
+
table = Table.new(table) if table.is_a?(Hash)
|
99
|
+
table.client = self
|
100
|
+
send(:delete, "/tables/#{table.name}")
|
101
|
+
return nil
|
82
102
|
end
|
83
103
|
|
84
104
|
|
85
105
|
####################################
|
86
|
-
#
|
106
|
+
# Property API
|
87
107
|
####################################
|
88
108
|
|
89
|
-
#
|
109
|
+
# Retrieves a list of all properties on a table.
|
90
110
|
#
|
91
|
-
# @
|
92
|
-
def
|
93
|
-
|
111
|
+
# @return [Array] the list of properties on the table.
|
112
|
+
def get_properties(table, options={})
|
113
|
+
raise ArgumentError.new("Table required") if table.nil?
|
114
|
+
properties = send(:get, "/tables/#{table.name}/properties")
|
115
|
+
properties.map!{|p| Property.new().from_hash(p)}
|
116
|
+
return properties
|
94
117
|
end
|
95
118
|
|
96
|
-
# Retrieves
|
119
|
+
# Retrieves a single property by name.
|
97
120
|
#
|
98
|
-
# @param [
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
return
|
121
|
+
# @param [Table] table The table to retrieve from.
|
122
|
+
# @param [String] name The name of the property to retrieve.
|
123
|
+
#
|
124
|
+
# @return [Array] the list of properties on the table.
|
125
|
+
def get_property(table, name, options={})
|
126
|
+
raise ArgumentError.new("Table required") if table.nil?
|
127
|
+
data = send(:get, "/tables/#{table.name}/properties/#{name}")
|
128
|
+
return Property.new().from_hash(data)
|
106
129
|
end
|
107
130
|
|
108
|
-
|
109
|
-
####################################
|
110
|
-
# Property Messages
|
111
|
-
####################################
|
112
|
-
|
113
|
-
# Adds a property to the server.
|
131
|
+
# Creates a property on a table.
|
114
132
|
#
|
115
|
-
# @param [Property] property the property to
|
116
|
-
def
|
117
|
-
|
133
|
+
# @param [Property] property the property to create.
|
134
|
+
def create_property(table, property, options={})
|
135
|
+
raise ArgumentError.new("Table required") if table.nil?
|
136
|
+
raise ArgumentError.new("Property required") if property.nil?
|
137
|
+
property = Property.new(property) if property.is_a?(Hash)
|
138
|
+
data = send(:post, "/tables/#{table.name}/properties", property.to_hash)
|
139
|
+
return property.from_hash(data)
|
118
140
|
end
|
119
141
|
|
120
|
-
#
|
142
|
+
# Updates a property on a table.
|
121
143
|
#
|
122
|
-
# @param [
|
123
|
-
def
|
124
|
-
|
144
|
+
# @param [Property] property the property to update.
|
145
|
+
def update_property(table, property, options={})
|
146
|
+
raise ArgumentError.new("Table required") if table.nil?
|
147
|
+
raise ArgumentError.new("Property required") if property.nil?
|
148
|
+
raise ArgumentError.new("Property name required") if property.name.to_s == ''
|
149
|
+
property = Property.new(property) if property.is_a?(Hash)
|
150
|
+
data = send(:patch, "/tables/#{table.name}/properties/#{property.name}", property.to_hash)
|
151
|
+
return property.from_hash(data)
|
125
152
|
end
|
126
153
|
|
127
|
-
#
|
128
|
-
|
129
|
-
|
154
|
+
# Deletes a property on a table.
|
155
|
+
#
|
156
|
+
# @param [Property] property the property to delete.
|
157
|
+
def delete_property(table, property, options={})
|
158
|
+
raise ArgumentError.new("Table required") if table.nil?
|
159
|
+
raise ArgumentError.new("Property required") if property.nil?
|
160
|
+
raise ArgumentError.new("Property name required") if property.name.to_s == ''
|
161
|
+
property = Property.new(property) if property.is_a?(Hash)
|
162
|
+
send(:delete, "/tables/#{table.name}/properties/#{property.name}")
|
163
|
+
return nil
|
130
164
|
end
|
131
165
|
|
132
166
|
|
133
167
|
####################################
|
134
|
-
# Event
|
168
|
+
# Event API
|
135
169
|
####################################
|
136
170
|
|
137
|
-
#
|
171
|
+
# Retrieves all events for a given object.
|
138
172
|
#
|
139
|
-
# @
|
140
|
-
def
|
141
|
-
|
173
|
+
# @return [Array] the list of events on the table.
|
174
|
+
def get_events(table, object_id, options={})
|
175
|
+
raise ArgumentError.new("Table required") if table.nil?
|
176
|
+
raise ArgumentError.new("Object identifier required") if object_id.nil?
|
177
|
+
events = send(:get, "/tables/#{table.name}/objects/#{object_id}/events")
|
178
|
+
events.map!{|e| Event.new().from_hash(e)}
|
179
|
+
return events
|
142
180
|
end
|
143
181
|
|
144
|
-
|
145
|
-
####################################
|
146
|
-
# Path Messages
|
147
|
-
####################################
|
148
|
-
|
149
|
-
# Finds a count of the action that occurs immediately after a set of
|
150
|
-
# actions.
|
182
|
+
# Retrieves the event that occurred at a given point in time for an object.
|
151
183
|
#
|
152
|
-
# @
|
153
|
-
def
|
154
|
-
|
184
|
+
# @return [Event] the event.
|
185
|
+
def get_event(table, object_id, timestamp, options={})
|
186
|
+
raise ArgumentError.new("Table required") if table.nil?
|
187
|
+
raise ArgumentError.new("Object identifier required") if object_id.nil?
|
188
|
+
raise ArgumentError.new("Timestamp required") if timestamp.nil?
|
189
|
+
data = send(:get, "/tables/#{table.name}/objects/#{object_id}/events/#{SkyDB.format_timestamp(timestamp)}")
|
190
|
+
return Event.new().from_hash(data)
|
155
191
|
end
|
156
192
|
|
157
|
-
|
158
|
-
####################################
|
159
|
-
# Utility message
|
160
|
-
####################################
|
161
|
-
|
162
|
-
# Checks if the server is up and running.
|
193
|
+
# Adds an event to an object.
|
163
194
|
#
|
164
|
-
# @
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
195
|
+
# @param [Table] table the table the object belongs to.
|
196
|
+
# @param [String] object_id the object's identifier.
|
197
|
+
# @param [Event] event the event to add.
|
198
|
+
#
|
199
|
+
# @return [Event] the event.
|
200
|
+
def add_event(table, object_id, event, options={})
|
201
|
+
options = {:method => :merge}.merge(options)
|
202
|
+
|
203
|
+
raise ArgumentError.new("Table required") if table.nil?
|
204
|
+
raise ArgumentError.new("Object identifier required") if object_id.nil?
|
205
|
+
raise ArgumentError.new("Event required") if event.nil?
|
206
|
+
event = Event.new(event) if event.is_a?(Hash)
|
207
|
+
raise ArgumentError.new("Event timestamp required") if event.timestamp.nil?
|
208
|
+
|
209
|
+
# The insertion method is communicated to the server through the HTTP method.
|
210
|
+
http_method = case options[:method]
|
211
|
+
when :replace then :put
|
212
|
+
when :merge then :patch
|
213
|
+
else raise ArgumentError.new("Invalid event insertion method: #{options[:method]}")
|
214
|
+
end
|
173
215
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
return nil
|
216
|
+
# Send the event and parse it when it comes back. It could have changed.
|
217
|
+
data = send(http_method, "/tables/#{table.name}/objects/#{object_id}/events/#{SkyDB.format_timestamp(event.timestamp)}", event.to_hash)
|
218
|
+
return event.from_hash(data)
|
178
219
|
end
|
179
220
|
|
180
|
-
|
181
|
-
####################################
|
182
|
-
# Lua Messages
|
183
|
-
####################################
|
184
|
-
|
185
|
-
# Executes a Lua aggregation job on the server and returns the results.
|
221
|
+
# Deletes an event for an object on a table.
|
186
222
|
#
|
187
|
-
# @param [
|
188
|
-
|
189
|
-
|
223
|
+
# @param [Table] table the table the object belongs to.
|
224
|
+
# @param [String] object_id the object's identifier.
|
225
|
+
# @param [Event] event the event to delete.
|
226
|
+
def delete_event(table, object_id, event, options={})
|
227
|
+
raise ArgumentError.new("Table required") if table.nil?
|
228
|
+
raise ArgumentError.new("Object identifier required") if object_id.nil?
|
229
|
+
raise ArgumentError.new("Event required") if event.nil?
|
230
|
+
event = Event.new(event) if event.is_a?(Hash)
|
231
|
+
raise ArgumentError.new("Event timestamp required") if event.timestamp.nil?
|
232
|
+
send(:delete, "/tables/#{table.name}/objects/#{object_id}/events/#{SkyDB.format_timestamp(event.timestamp)}")
|
233
|
+
return nil
|
190
234
|
end
|
191
235
|
|
192
236
|
|
193
237
|
####################################
|
194
|
-
# Query
|
238
|
+
# Query API
|
195
239
|
####################################
|
196
240
|
|
197
|
-
#
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
# Starts a query with a single selection against the database.
|
241
|
+
# Runs a query against a given table.
|
242
|
+
#
|
243
|
+
# @param [Table] table The table to query.
|
244
|
+
# @param [Hash] q The query definition to run.
|
203
245
|
#
|
204
|
-
# @
|
205
|
-
def
|
206
|
-
|
246
|
+
# @return [Results] the results of the query.
|
247
|
+
def query(table, q)
|
248
|
+
raise ArgumentError.new("Table required") if table.nil?
|
249
|
+
raise ArgumentError.new("Query definition required") if q.nil?
|
250
|
+
q = {:steps => q} if q.is_a?(Array)
|
251
|
+
return send(:post, "/tables/#{table.name}/query", q)
|
207
252
|
end
|
208
253
|
|
209
254
|
|
210
255
|
####################################
|
211
|
-
#
|
256
|
+
# Utility API
|
212
257
|
####################################
|
213
258
|
|
214
|
-
#
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
# Create multi-message.
|
219
|
-
@multi_message = SkyDB::Message::Multi.new(options)
|
220
|
-
@multi_message_max_count = options[:max_count].to_i
|
221
|
-
|
222
|
-
# Execute the block normally and send the message.
|
259
|
+
# Pings the server to determine if it is running.
|
260
|
+
#
|
261
|
+
# @return [Boolean] true if the server is running, otherwise false.
|
262
|
+
def ping(options={})
|
223
263
|
begin
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
if @multi_message.messages.length > 0
|
228
|
-
send_message(@multi_message)
|
229
|
-
end
|
230
|
-
|
231
|
-
ensure
|
232
|
-
@multi_message = nil
|
264
|
+
send(:get, "/ping")
|
265
|
+
rescue
|
266
|
+
return false
|
233
267
|
end
|
234
|
-
|
235
|
-
return nil
|
268
|
+
return true
|
236
269
|
end
|
237
|
-
|
270
|
+
|
238
271
|
|
239
272
|
####################################
|
240
|
-
#
|
273
|
+
# HTTP Utilities
|
241
274
|
####################################
|
242
|
-
|
243
|
-
#
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
message.validate!
|
253
|
-
|
254
|
-
# If this is part of a multi message then simply append the message for
|
255
|
-
# later sending.
|
256
|
-
if !@multi_message.nil? && @multi_message != message
|
257
|
-
@multi_message.messages << message
|
258
|
-
|
259
|
-
# Send off the MULTI if the message count is above our limit.
|
260
|
-
if @multi_message_max_count > 0 && @multi_message.messages.length >= @multi_message_max_count
|
261
|
-
send_message(@multi_message)
|
262
|
-
@multi_message = SkyDB::Message::Multi.new()
|
275
|
+
|
276
|
+
# Executes a RESTful JSON over HTTP POST.
|
277
|
+
def send(method, path, data=nil)
|
278
|
+
# Generate a JSON request.
|
279
|
+
request = case method
|
280
|
+
when :get then Net::HTTP::Get.new(path)
|
281
|
+
when :post then Net::HTTP::Post.new(path)
|
282
|
+
when :patch then Net::HTTP::Patch.new(path)
|
283
|
+
when :put then Net::HTTP::Put.new(path)
|
284
|
+
when :delete then Net::HTTP::Delete.new(path)
|
263
285
|
end
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
# Otherwise send the message immediately.
|
268
|
-
else
|
269
|
-
begin
|
270
|
-
# Connect to the server.
|
271
|
-
socket = TCPSocket.new(host, port.to_i)
|
272
|
-
|
273
|
-
# Encode and send message request.
|
274
|
-
message.encode(socket)
|
275
|
-
|
276
|
-
# Retrieve the respose as a buffer so we can inspect it.
|
277
|
-
#msg, x = *socket.recvmsg
|
278
|
-
#buffer = StringIO.new(msg)
|
279
|
-
#puts "[#{message.message_name}]< #{buffer.string.to_hex}" if SkyDB.debug
|
286
|
+
request.add_field('Content-Type', 'application/json')
|
287
|
+
request.body = JSON.generate(data, :max_nesting => 200) unless data.nil?
|
288
|
+
response = Net::HTTP.new(host, port).start {|http| http.request(request) }
|
280
289
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
unpacker.each do |obj|
|
285
|
-
response = obj
|
286
|
-
break
|
287
|
-
end
|
290
|
+
# Parse the body as JSON.
|
291
|
+
json = JSON.parse(response.body) rescue nil
|
292
|
+
message = json['message'] rescue nil
|
288
293
|
|
289
|
-
|
290
|
-
socket.close()
|
291
|
-
|
292
|
-
# TODO: Exception processing.
|
293
|
-
|
294
|
-
# Process response back through the message.
|
295
|
-
response = message.process_response(response)
|
296
|
-
|
297
|
-
# Return response.
|
298
|
-
return response
|
294
|
+
warn("#{method.to_s.upcase} #{path}: #{request.body} -> #{response.body}") if SkyDB.debug
|
299
295
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
296
|
+
# Process based on the response code.
|
297
|
+
case response
|
298
|
+
when Net::HTTPSuccess then
|
299
|
+
return json
|
300
|
+
else
|
301
|
+
e = ServerError.new(message)
|
302
|
+
e.status = response.code
|
303
|
+
raise e
|
304
304
|
end
|
305
305
|
end
|
306
306
|
end
|