orient_db_client 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -14,52 +14,142 @@ Supported OrientDB Releases
14
14
  I've tested this against OrientDB-1.0rc9 which is the current official release as of writing this README.
15
15
 
16
16
 
17
+ Supported Ruby Versions
18
+ ---------------------------
19
+
20
+ This gem has only been tested on 1.9.3. It *should* run on any 1.9 install, and will definitely NOT run on 1.8 due to the use of Encoding. Compatibility with 1.8 is planned, but not scheduled for any particular milestone yet.
21
+
22
+
17
23
  Basic Usage
18
24
  -----------
19
25
 
26
+ There are two classifications of interaction with the OrientDB server: Server and Database.
27
+
28
+ A server session is used for creating and deleting databases, as well as confirming their existence. (Setting and reading the server configuration is also part of the protocol, but not yet supported by this gem.)
29
+
30
+ A database session is used to performed all other work on a database, including but not limited to record CRUD operations, querying, and managing clusters (which are the physical files and logical subdivisions of an OrientDB database, not to be confused with clustering in the networking sense.)
31
+
32
+ ## Connecting to an OrientDB Server
33
+
34
+ Before obtaining server or database sessions, a connection must be made to an OrientDB server instance. There isn't much to this part.
35
+
36
+ require 'orient_db_client'
37
+
38
+ connection = OrientDBClient.connect('localhost')
39
+
40
+ If you need to specify the port, pass it in the options Hash:
41
+
42
+ connection = OrientDBClient.connect('localhost', :port => 2424)
43
+
44
+ When you're done with the connection (and all of the sessions you have opened within it):
45
+
46
+ connection.close
20
47
 
21
48
  ## Server Operations
22
49
 
23
- require 'orient_db_client`
50
+ A server session is only needed when an application wants to create, delete, or confirm the existence of a database.
24
51
 
25
- connection = OrientDbClient.connect('0.0.0.0', { :port => 2424 })
52
+ To obtain a server session, call #open_server on the connection. This requires user credentials from the `<users>` section of the OrientDB server's `orientdb-server-config.xml` file.
26
53
 
27
54
  server = connection.open_server({
28
55
  :user => 'root',
29
56
  :password => '<password>'
30
57
  })
31
58
 
59
+ **NOTE:** *I strongly suggest figuring out OrientDB's permission system and creating a non-root user in Orient's config.xml. :)*
60
+
61
+ Create a database using local storage (support for in-memory databases forthcoming):
62
+
32
63
  server.create_local_database("my_database")
33
64
 
34
- server.delete_database(database_name)
65
+ Confirm that a database exists:
35
66
 
67
+ server.database_exists? "my_database"
68
+
69
+ Delete a database:
70
+
71
+ server.delete_database(my_database)
36
72
 
37
- ## Database Operations
38
73
 
39
- require 'orient_db_client`
74
+ ## Database Operations
40
75
 
41
- connection = OrientDbClient.connect('0.0.0.0', { :port => 2424 })
76
+ Most work in OrientDB will be done with database sessions. To open one:
42
77
 
43
78
  database = connection.open_database(database_name, {
44
79
  :user => 'admin',
45
80
  :password => 'admin'
46
81
  })
47
82
 
48
- cluster_id = database.create_physical_cluster("test")
83
+ **NOTE:** *By default, OrientDB databases have three users pre-created, `reader`, `writer`, and `admin`. Their passwords are the same as their names. Don't forget to change these before running your OrientDB server in production. :)*
84
+
85
+
86
+ ### CRUD
87
+
88
+ By default, a database contains the following clusters: internal, index, default, orids, orole, and ouser. (I'm not entirely sure what that default cluster is for, so I don't write to it. It may be an all-purpose starter cluster though.)
89
+
90
+ Before records can be stored in the database, a cluster must be created to contain them. Create one like this:
91
+
92
+ cluster_id = database.create_physical_cluster("mycluster")
49
93
 
50
- record = { :document => { 'key1' => 'value1' } }
94
+ This adds a physical (file) cluster to the database. (Support for logical clusters forthcoming.)
95
+
96
+ This gem was written to be somewhat liberal with what it will accept as a valid record Hash. The gem will make implicit decisions about how to serialize each of the values.
97
+
98
+ The following is an acceptable record:
99
+
100
+ record = { :key1 => 'value1', 'key2' => 2, 'key3' => 3.45 }
101
+
102
+ The symbolic `:key1` will be converted into a string. Key2's value will be stored as an integer. Key3's value will be stored as a double.
103
+
104
+ To gain more explicit control over serialization, a record must conform to the following structure:
105
+
106
+ record = { :document => { :key1 => 'value1', 'key2' => 2, 'key3' => 3.45 },
107
+ :structure => { 'key1' => :string, 'key2' => :integer, 'key3' => :double },
108
+ :class => "MyClass" }
109
+
110
+ **NOTE:** The `:class` is optional. It is only useful in databases that use classes to implement a schema.
111
+
112
+ Creating a record is straightforward:
51
113
 
52
114
  rid = database.create_record(cluster_id, record)
53
115
 
116
+ The return value is an OrientDbClient::Rid. You can get the native "#i:p" form by calling #to_s on the returned Rid.
117
+
118
+ An existing record can be read using #load_Record:
119
+
54
120
  loaded_record = database.load_record(rid)
55
- loaded_record[:document]['key1'] = 'updated'
56
121
 
122
+ Records returned by #load_record will contain the above `:document` and `:structure` keys, along with `:record_version`, `:cluster_id`, and `:cluster_position`. `:class` will be provided if the record has a class.
123
+
124
+ To update the record:
125
+
126
+ loaded_record[:document]['key1'] = 'updated'
57
127
  version = database.update_record(loaded_record, rid, :incremental)
58
128
 
59
- edited_record = database.load_record(rid)
129
+ The updated record is stored to the database, and its new version number is returned. The `:incremental` option tells OrientDB to increment the record's version number when persisting the record. Alternatively, `:none` can be passed and OrientDB will not perform any type of versioning. Lastly, an explicit numeric version can be passed and it will be used as the record's new version number.
130
+
131
+ **NOTE:** OrientDB does not currently retain old records. It isn't so much "version control" as version marking.
132
+
133
+
134
+ To delete a record:
135
+
136
+ database.delete_record(rid, version)
137
+
138
+ The version must match the version number of the record as it is currently stored in the database.
139
+
140
+
141
+ ### Querying (Experimental)
142
+
143
+ OrientDB implements a SQL-like language that can be used to query records, add/alter/remove clusters, add/alter/remove classes, and more. See the [SQL section](http://code.google.com/p/orient/wiki/SQL) of OrientDB's Wiki for more information.
144
+
145
+
146
+ Use the #query method to send a query. **Be careful with this method.** Parameterized queries and sanitization have not been implemented in the gem. Insufficient sanitization of SQL strings sent to this method could open up the database to SQL Injection attacks. While OrientDB's SQL language is still evolving, it will be difficult to know what kind of vulnerabilities exist.
147
+
148
+ database.query "SELECT FROM cluster:mycluster"
60
149
 
61
- database.delete_record(rid, edited_record[:record_version])
150
+ This should return an array of deserialized records.
62
151
 
152
+ **NOTE: Expect this to be buggy right now.** *OrientDB's protocol mentions several possible return values from a query, but I've only been able to get it to return record collections in practice. As such, I've not coded for the possibility of getting back a single record, getting back raw data, or getting back a flat response. I'm not even sure what the latter two look like when they come out of the OrientDB server.*
63
153
 
64
154
  Testing
65
155
  -------
@@ -212,18 +212,15 @@ module OrientDbClient
212
212
  end
213
213
 
214
214
  def self.db_create(socket, session, database, options = {})
215
- if options.is_a?(String)
216
- options = { :storage_type => options }
217
- end
215
+ if options.is_a?(String) || options.is_a?(Symbol)
216
+ options = { :storage_type => options }
217
+ end
218
218
 
219
- options = { :storage_type => 'local' }.merge(options)
219
+ options = { :storage_type => 'local' }.merge(options)
220
220
 
221
- socket.write NetworkMessage.new { |m|
222
- m.add :byte, Operations::DB_CREATE
223
- m.add :integer, session
224
- m.add :string, database
225
- m.add :string, options[:storage_type]
226
- }.pack
221
+ options[:storage_type] = options[:storage_type].to_s
222
+
223
+ socket.write make_db_create_message(session, database, options).pack
227
224
 
228
225
  read_response(socket)
229
226
 
@@ -385,6 +382,19 @@ module OrientDbClient
385
382
 
386
383
  private
387
384
 
385
+ def self.make_db_create_message(*args)
386
+ session = args.shift
387
+ database = args.shift
388
+ options = args.shift
389
+
390
+ NetworkMessage.new { |m|
391
+ m.add :byte, Operations::DB_CREATE
392
+ m.add :integer, session
393
+ m.add :string, database
394
+ m.add :string, options[:storage_type].to_s
395
+ }
396
+ end
397
+
388
398
  def self.read_byte(socket)
389
399
  socket.read(1).unpack('C').first
390
400
  end
@@ -31,21 +31,10 @@ module OrientDbClient
31
31
  end
32
32
 
33
33
  options = {
34
- :database_type => 'document',
35
- :storage_type => 'local'
34
+ :database_type => 'document'
36
35
  }.merge(options)
37
36
 
38
- socket.write NetworkMessage.new { |m|
39
- m.add :byte, Operations::DB_CREATE
40
- m.add :integer, session
41
- m.add :string, database
42
- m.add :string, options[:database_type]
43
- m.add :string, options[:storage_type]
44
- }.pack
45
-
46
- read_response(socket)
47
-
48
- { :session => read_integer(socket) }
37
+ super
49
38
  end
50
39
 
51
40
  def self.db_open(socket, database, options = {})
@@ -83,6 +72,23 @@ module OrientDbClient
83
72
  { :session => read_integer(socket),
84
73
  :message_content => read_record_load(socket) }
85
74
  end
75
+
76
+ private
77
+
78
+ def self.make_db_create_message(*args)
79
+ session = args.shift
80
+ database = args.shift
81
+ options = args.shift
82
+
83
+ NetworkMessage.new { |m|
84
+ m.add :byte, Operations::DB_CREATE
85
+ m.add :integer, session
86
+ m.add :string, database
87
+ m.add :string, options[:database_type].to_s
88
+ m.add :string, options[:storage_type].to_s
89
+ }
90
+ end
91
+
86
92
  end
87
93
  end
88
94
  end
@@ -35,7 +35,8 @@ module OrientDbClient
35
35
  end
36
36
 
37
37
  document.each do |k, v|
38
- result << "#{k}:#{serialize_item(v, structure[k])}"
38
+ key_struct = structure[k.to_s] || structure[k.to_sym]
39
+ result << "#{k}:#{serialize_item(v, key_struct)}"
39
40
  end
40
41
 
41
42
  serialized_document = "#{recordClass}#{result.join(",")}"
@@ -109,6 +110,8 @@ module OrientDbClient
109
110
  serialize_double(value)
110
111
  when :float
111
112
  serialize_float(value)
113
+ when :integer
114
+ serialize_integer(value)
112
115
  when :long
113
116
  serialize_long(value)
114
117
  when :map
@@ -3,7 +3,15 @@ require 'orient_db_client/session'
3
3
  module OrientDbClient
4
4
  class ServerSession < Session
5
5
  def create_local_database(database, options = {})
6
- @connection.create_database(@id, database)
6
+ options[:storage_type] = :local
7
+
8
+ @connection.create_database(@id, database, options)
9
+ end
10
+
11
+ def create_memory_database(database, options = {})
12
+ options[:storage_type] = :memory
13
+
14
+ @connection.create_database(@id, database, options)
7
15
  end
8
16
 
9
17
  def database_exists?(database)
@@ -1,3 +1,3 @@
1
1
  module OrientDbClient
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -34,4 +34,19 @@ class TestServerSession < MiniTest::Unit::TestCase
34
34
  @session.delete_database(database) if @session.database_exists?(database)
35
35
  end
36
36
  end
37
+
38
+ def test_create_and_delete_memory_database_commands
39
+ skip # Bug in OrientDB-1.0rc9 prevents this test from passing
40
+
41
+ database = "test_create_memory_database"
42
+
43
+ @session.delete_database(database) if @session.database_exists?(database)
44
+
45
+ begin
46
+ @session.create_memory_database(database)
47
+ assert @session.database_exists?(database)
48
+ ensure
49
+ @session.delete_database(database) if @session.database_exists?(database)
50
+ end
51
+ end
37
52
  end
@@ -9,7 +9,7 @@ class TestSerializer7 < MiniTest::Unit::TestCase
9
9
  record = {
10
10
  :class => 'OClass',
11
11
  :structure => {
12
- 'buffer' => :binary,
12
+ :buffer => :binary,
13
13
  'true' => :boolean,
14
14
  'false' => :boolean,
15
15
  'byte' => :byte,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: orient_db_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-05 00:00:00.000000000 Z
12
+ date: 2012-04-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -123,12 +123,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
123
  - - ! '>='
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
+ segments:
127
+ - 0
128
+ hash: 2784375670515319189
126
129
  required_rubygems_version: !ruby/object:Gem::Requirement
127
130
  none: false
128
131
  requirements:
129
132
  - - ! '>='
130
133
  - !ruby/object:Gem::Version
131
134
  version: '0'
135
+ segments:
136
+ - 0
137
+ hash: 2784375670515319189
132
138
  requirements: []
133
139
  rubyforge_project: orient_db_client
134
140
  rubygems_version: 1.8.21