orientdb-binary 0.6.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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +64 -0
  7. data/lib/orientdb_binary.rb +25 -0
  8. data/lib/orientdb_binary/base.rb +40 -0
  9. data/lib/orientdb_binary/config.rb +5 -0
  10. data/lib/orientdb_binary/connection.rb +17 -0
  11. data/lib/orientdb_binary/database.rb +24 -0
  12. data/lib/orientdb_binary/database_operations/base_operations.rb +70 -0
  13. data/lib/orientdb_binary/database_operations/data_cluster.rb +116 -0
  14. data/lib/orientdb_binary/database_operations/data_segment.rb +31 -0
  15. data/lib/orientdb_binary/database_operations/query.rb +58 -0
  16. data/lib/orientdb_binary/database_operations/record.rb +105 -0
  17. data/lib/orientdb_binary/database_operations/transaction.rb +8 -0
  18. data/lib/orientdb_binary/operation_types.rb +51 -0
  19. data/lib/orientdb_binary/parser/deserializer.rb +161 -0
  20. data/lib/orientdb_binary/parser/serializer.rb +83 -0
  21. data/lib/orientdb_binary/protocols/base.rb +42 -0
  22. data/lib/orientdb_binary/protocols/bindata_primitives.rb +46 -0
  23. data/lib/orientdb_binary/protocols/command.rb +166 -0
  24. data/lib/orientdb_binary/protocols/config_get.rb +22 -0
  25. data/lib/orientdb_binary/protocols/config_list.rb +24 -0
  26. data/lib/orientdb_binary/protocols/config_set.rb +22 -0
  27. data/lib/orientdb_binary/protocols/connect.rb +26 -0
  28. data/lib/orientdb_binary/protocols/datacluster_add.rb +26 -0
  29. data/lib/orientdb_binary/protocols/datacluster_count.rb +26 -0
  30. data/lib/orientdb_binary/protocols/datacluster_datarange.rb +23 -0
  31. data/lib/orientdb_binary/protocols/datacluster_drop.rb +22 -0
  32. data/lib/orientdb_binary/protocols/datacluster_lh_cluster_is_used.rb +20 -0
  33. data/lib/orientdb_binary/protocols/datasegment_add.rb +24 -0
  34. data/lib/orientdb_binary/protocols/datasegment_drop.rb +23 -0
  35. data/lib/orientdb_binary/protocols/db_close.rb +16 -0
  36. data/lib/orientdb_binary/protocols/db_countrecords.rb +20 -0
  37. data/lib/orientdb_binary/protocols/db_create.rb +23 -0
  38. data/lib/orientdb_binary/protocols/db_drop.rb +22 -0
  39. data/lib/orientdb_binary/protocols/db_exist.rb +23 -0
  40. data/lib/orientdb_binary/protocols/db_freeze.rb +21 -0
  41. data/lib/orientdb_binary/protocols/db_list.rb +26 -0
  42. data/lib/orientdb_binary/protocols/db_open.rb +43 -0
  43. data/lib/orientdb_binary/protocols/db_release.rb +21 -0
  44. data/lib/orientdb_binary/protocols/db_reload.rb +26 -0
  45. data/lib/orientdb_binary/protocols/db_size.rb +20 -0
  46. data/lib/orientdb_binary/protocols/errors.rb +28 -0
  47. data/lib/orientdb_binary/protocols/record_create.rb +35 -0
  48. data/lib/orientdb_binary/protocols/record_delete.rb +25 -0
  49. data/lib/orientdb_binary/protocols/record_load.rb +65 -0
  50. data/lib/orientdb_binary/protocols/record_update.rb +27 -0
  51. data/lib/orientdb_binary/protocols/shutdown.rb +21 -0
  52. data/lib/orientdb_binary/server.rb +71 -0
  53. data/orientdb-binary.gemspec +26 -0
  54. data/test/database/test_database.rb +193 -0
  55. data/test/database/test_deserializer.rb +140 -0
  56. data/test/database/test_serializer.rb +55 -0
  57. data/test/server/test_server.rb +73 -0
  58. data/test/test_helper.rb +9 -0
  59. metadata +162 -0
@@ -0,0 +1,31 @@
1
+ require 'orientdb_binary/protocols/datasegment_add'
2
+ require 'orientdb_binary/protocols/datasegment_drop'
3
+
4
+ module OrientdbBinary
5
+ module DatabaseOperations
6
+ module DataSegment
7
+
8
+ # name: string
9
+ # location: string
10
+ # Usage:
11
+ # db.add_datasegment(name: "posts")
12
+ # db.add_datasegment(name: "posts", location: "posts_segments")
13
+ #
14
+ def add_datasegment(args)
15
+ default = {
16
+ location: args[:name] + "_segments"
17
+ }
18
+ options = default.merge(args)
19
+ OrientdbBinary::Protocols::DatasegmentAdd.new(params(options)).process(socket)
20
+ end
21
+
22
+ # name: string
23
+ # Usage:
24
+ # db.drop_datasegment(name: 'posts')
25
+ #
26
+ def drop_datasegment(args)
27
+ OrientdbBinary::Protocols::DatasegmentDrop.new(params(args)).process(socket)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,58 @@
1
+ require 'orientdb_binary/protocols/command'
2
+
3
+ module OrientdbBinary
4
+ module DatabaseOperations
5
+ module Query
6
+ def query(text, params, fetch_plan="*:0")
7
+ class_name = 'com.orientechnologies.orient.core.sql.query.OSQLSynchQuery'
8
+ serialized_params = OrientdbBinary::Parser::Serializer.new.serialize_document({params: params})
9
+ q = OrientdbBinary::Protocols::SqlCommandPayload.new text: text, serialized_params: serialized_params,
10
+ fetch_plan: fetch_plan,
11
+ class_name: class_name
12
+ _command(q.to_binary_s, class_name)
13
+ end
14
+
15
+ # def script(text)
16
+ # class_name = 'com.orientechnologies.orient.core.sql.OCommandSQL'
17
+ # end
18
+
19
+ def command(text, params={})
20
+ class_name = 'com.orientechnologies.orient.core.sql.OCommandSQL'
21
+ fetch_plan = nil
22
+ serialized_params = OrientdbBinary::Parser::Serializer.new.serialize_document({params: params})
23
+ q = OrientdbBinary::Protocols::SqlCommandPayload.new text: text, serialized_params: serialized_params,
24
+ fetch_plan: fetch_plan,
25
+ class_name: class_name
26
+ _command(q.to_binary_s, class_name)
27
+ end
28
+
29
+ # def command(text)
30
+ # mode = 's'.ord
31
+ # class_name = 'com.orientechnologies.orient.core.sql.query.OSQLSynchQuery'
32
+ # fetchplan = "*0"
33
+
34
+ # query = OrientdbBinary::Protocols::SqlCommandPayload.new text: text, non_text_limit: -1, fetchplan: fetchplan
35
+ # p query
36
+
37
+ # # command = OrientdbBinary::Protocols::Command.new session: session, mode: mode, clazz_name: class_name, command_payload_length: query.to_binary_s.length, command_payload: query.to_binary_s
38
+ # command = OrientdbBinary::Protocols::Command.new session: session, mode: mode, text: text, command_payload: query.to_binary_s
39
+ # command.write(socket)
40
+
41
+ # status = BinData::Int8.read(socket).to_i
42
+ # process_errors(status)
43
+
44
+ # p OrientdbBinary::Protocols::CommandAnswer.read(socket)
45
+ # end
46
+
47
+ private
48
+ def _command(binary_query, class_name)
49
+ mode = 's'.ord
50
+ OrientdbBinary::Protocols::Command.new(
51
+ session: session, mode: mode,
52
+ command_payload_length: binary_query.length,
53
+ command_payload: binary_query
54
+ ).process(socket)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,105 @@
1
+ require 'orientdb_binary/protocols/record_load'
2
+ require 'orientdb_binary/protocols/record_create'
3
+ require 'orientdb_binary/protocols/record_update'
4
+ require 'orientdb_binary/protocols/record_delete'
5
+ require 'orientdb_binary/protocols/db_countrecords'
6
+
7
+ module OrientdbBinary
8
+ module DatabaseOperations
9
+ module Record
10
+
11
+ # rid: #id:position / id:position
12
+ # or
13
+ # cluster_id: int
14
+ # cluster:position: int
15
+ # optional
16
+ # fetch_plan: string (by default used "*:0")
17
+ # ignore_cache: int (0-1, by default 1)
18
+ # load_tombstones: int (0-1, by default 0)
19
+ # Usage:
20
+ # db.load_record("#5:2")
21
+ # db.load_record("#5:2", fetch_plan: "*:-1")
22
+ # db.load_record(5, 2, fetch_plan: "*:-1", ignore_cache: 0, load_tombstones: 1)
23
+ #
24
+ def load_record(args)
25
+ if args[:rid]
26
+ match = args[:rid].match(/#*(?<id>\d+):(?<position>\d+)/)
27
+ args[:cluster_id] = match[:id].to_i
28
+ args[:cluster_position] = match[:position].to_i
29
+ end
30
+ defaults = {
31
+ fetch_plan: "*:0",
32
+ ignore_cache: 1,
33
+ load_tombstones: 0
34
+ }
35
+ options = defaults.merge(args)
36
+ answer = OrientdbBinary::Protocols::RecordLoad.new(params(options)).process(socket)
37
+ answer.process(options)
38
+ end
39
+
40
+ # Create record from object
41
+ # Usage:
42
+ # record = {
43
+ # :@class => "Posts",
44
+ # :@type => "d",
45
+ # :@cluster => "posts"
46
+ # name: "some name"
47
+ # param: "some param"
48
+ # }
49
+ # Usage:
50
+ # db.create_record_from_object(record)
51
+ #
52
+ def create_record_from_object(record)
53
+ record_type = record[:@type] ? record[:@type].ord : "d".ord
54
+ cluster_id = (cluster = find_datacluster_by(cluster_name: 'default')) ? cluster[:cluster_id] : nil
55
+
56
+ if record[:@cluster]
57
+ if record[:@cluster].is_a? Integer
58
+ cluster_id = record[:@cluster]
59
+ else
60
+ cluster_id = (cluster = find_datacluster_by(cluster_name: record[:@cluster])) ? cluster[:cluster_id] : cluster_id
61
+ end
62
+ elsif record[:@class]
63
+ cluster_id = (cluster = find_datacluster_by(cluster_name: record[:@class])) ? cluster[:cluster_id] : cluster_id
64
+ end
65
+
66
+ record_content = OrientdbBinary::Parser::Serializer.new.serialize_document(record)
67
+ create_record(record_type: record_type, cluster_id: cluster_id, record_content: record_content)
68
+ end
69
+
70
+ # Create record
71
+ # cluster_id: int or cluster_name: string
72
+ # record_content: string -> it's serialized document; use create_record_from_object which serialize hash into string accepted by Orientdb
73
+ # Usage:
74
+ # db.create_record(cluster_id: 5, record_content: "Post@title=\"Post title\"")
75
+ #
76
+ def create_record(args)
77
+ if args[:cluster_name] and not args[:cluster_id]
78
+ args[:cluster_id] = (cluster = find_datacluster_by(cluster_name: args[:cluster_name])) ? cluster_id : nil
79
+ end
80
+
81
+ defaults = {
82
+ datasegment_id: -1,
83
+ record_type: "d".ord,
84
+ mode: 0
85
+ }
86
+
87
+ options = defaults.merge(args)
88
+ answer = OrientdbBinary::Protocols::RecordCreate.new(params(args)).process(socket)
89
+ answer.process(options)
90
+ end
91
+
92
+ def update_record(args)
93
+ OrientdbBinary::Protocols::RecordUpdate.new(params(args)).process(socket)
94
+ end
95
+
96
+ def delete_record(args)
97
+ OrientdbBinary::Protocols::RecordDelete.new(params(args)).process(socket)
98
+ end
99
+
100
+ def count_records
101
+ OrientdbBinary::Protocols::DbCountRecords.new(params).process(socket)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,8 @@
1
+ module OrientdbBinary
2
+ module DatabaseOperations
3
+ module Transaction
4
+ def tx_commit(args)
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,51 @@
1
+ module OrientdbBinary
2
+ module OperationTypes
3
+ NEW_SESSION = -1
4
+ REQUEST_SHUTDOWN = 1
5
+ REQUEST_CONNECT = 2
6
+ REQUEST_DB_OPEN = 3
7
+ REQUEST_DB_CREATE = 4
8
+ REQUEST_DB_CLOSE = 5
9
+ REQUEST_DB_EXIST = 6
10
+ REQUEST_DB_DROP = 7
11
+ REQUEST_DB_SIZE = 8
12
+ REQUEST_DB_COUNTRECORDS = 9
13
+ REQUEST_DATACLUSTER_ADD = 10
14
+ REQUEST_DATACLUSTER_DROP = 11
15
+ REQUEST_DATACLUSTER_COUNT = 12
16
+ REQUEST_DATACLUSTER_DATARANGE = 13
17
+ REQUEST_DATACLUSTER_COPY = 14
18
+ REQUEST_DATACLUSTER_LH_CLUSTER_IS_USED = 16
19
+ REQUEST_DATASEGMENT_ADD = 20
20
+ REQUEST_DATASEGMENT_DROP = 21
21
+ REQUEST_RECORD_METADATA = 29
22
+ REQUEST_RECORD_LOAD = 30
23
+ REQUEST_RECORD_CREATE = 31
24
+ REQUEST_RECORD_UPDATE = 32
25
+ REQUEST_RECORD_DELETE = 33
26
+ REQUEST_RECORD_COPY = 34
27
+ REQUEST_POSITIONS_HIGHER = 36
28
+ REQUEST_POSITIONS_LOWER = 37
29
+ REQUEST_RECORD_CLEAN_OUT = 38
30
+ REQUEST_POSITIONS_FLOOR = 39
31
+ REQUEST_COUNT = 40 # (DEPRECATED: USE REQUEST_DATACLUSTER_COUNT)
32
+ REQUEST_COMMAND = 41
33
+ REQUEST_POSITIONS_CEILING = 42
34
+ REQUEST_TX_COMMIT = 60
35
+ REQUEST_CONFIG_GET = 70
36
+ REQUEST_CONFIG_SET = 71
37
+ REQUEST_CONFIG_LIST = 72
38
+ REQUEST_DB_RELOAD = 73
39
+ REQUEST_DB_LIST = 74
40
+ REQUEST_PUSH_RECORD = 79
41
+ REQUEST_PUSH_DISTRIB_CONFIG = 80
42
+ REQUEST_DB_COPY = 90
43
+ REQUEST_REPLICATION = 91
44
+ REQUEST_CLUSTER = 92
45
+ REQUEST_DB_TRANSFER = 93
46
+ REQUEST_DB_FREEZE = 94
47
+ REQUEST_DB_RELEASE = 95
48
+ REQUEST_DATACLUSTER_FREEZE = 96
49
+ REQUEST_DATACLUSTER_RELEASE = 97
50
+ end
51
+ end
@@ -0,0 +1,161 @@
1
+ module OrientdbBinary
2
+ module Parser
3
+ class Deserializer
4
+ attr_accessor :record
5
+
6
+ def initialize()
7
+ @record = {}
8
+ end
9
+
10
+ def split(serialized, position)
11
+ first = serialized[0...position]
12
+ second = serialized[position+1..-1]
13
+ return first, second
14
+ end
15
+
16
+ def deserialize(document, params={})
17
+ @record = deserialize_document(document)
18
+ params.each do |k,v|
19
+ @record[k] = v
20
+ end
21
+ @record
22
+ end
23
+
24
+ def deserialize_document(serialized, document={}, is_map=false)
25
+ serialized = serialized.strip
26
+ class_index = serialized.index('@')
27
+ colon_index = serialized.index(':')
28
+ if class_index && (!colon_index || colon_index > class_index)
29
+ document[:@class], serialized = split(serialized, class_index)
30
+ end
31
+ document[:@type] = "d" unless is_map
32
+
33
+ while (serialized and field_index = serialized.index(':')) do
34
+ field, serialized = split(serialized, field_index)
35
+
36
+ if field[0] == "\"" and field[-1] == "\""
37
+ field = field[1..-2]
38
+ end
39
+
40
+ comma_index = look_for_comma_index(serialized)
41
+ value, serialized = split(serialized, comma_index)
42
+ value = deserialize_field_value(value)
43
+ document[field.to_sym] = value
44
+ end
45
+ document
46
+ end
47
+
48
+ def deserialize_field_value(value)
49
+ return nil if value.empty?
50
+
51
+ if ["true", "false"].include? value
52
+ return value == "true"
53
+ end
54
+
55
+ first_char = value[0]
56
+ last_char = value[-1]
57
+
58
+ if "\"" == first_char
59
+ val = value[1..-2]
60
+ val = val.gsub(/\\"/, "\"")
61
+ val = val.sub(/\\\\/, "\\")
62
+ return val
63
+ end
64
+
65
+ # split for date and datetime
66
+ if ["t", "a"].include? last_char
67
+ date = DateTime.strptime(value[0..-1],'%s')
68
+ date = date.to_date if last_char == "a"
69
+ return date
70
+ end
71
+
72
+ if "(" == first_char
73
+ return deserialize_document(value[1..-2])
74
+ end
75
+
76
+ if "{" == first_char
77
+ return deserialize_document(value[1..-2], {}, true)
78
+ end
79
+
80
+ if ["[", "<"].include? first_char
81
+ ret = [] if first_char == "["
82
+ ret = Set.new if first_char == "<"
83
+
84
+ values = split_values_from(value[1..-2])
85
+ values.each { |val| ret << deserialize_field_value(val) }
86
+ return ret
87
+ end
88
+
89
+ if "b" == last_char
90
+ return value[0..-2].to_i
91
+ end
92
+
93
+ # split for long/short?
94
+ if ["l", "s"].include? last_char
95
+ return value[0..-2].to_i
96
+ end
97
+
98
+ if "c" == last_char
99
+ return BigDecimal.new(value[0..-2].to_i)
100
+ end
101
+
102
+ if ["f", "d"].include? last_char
103
+ return value[0..-2].to_f
104
+ end
105
+
106
+ return value.to_i if value.to_i.to_s == value
107
+
108
+ return value
109
+ end
110
+
111
+ private
112
+
113
+ def split_values_from(value)
114
+ result = []
115
+ while value do
116
+ comma_at = look_for_comma_index(value)
117
+ res, value = split(value, comma_at)
118
+ result << res
119
+ end
120
+ result
121
+ end
122
+
123
+ def look_for_comma_index(serialized)
124
+ delimiters = []
125
+ (0...serialized.length).each do |idx|
126
+ current = serialized[idx]
127
+ if current == "," and delimiters.length == 0
128
+ return idx
129
+ elsif start_delimiter?(current) and delimiters[-1] != "\""
130
+ delimiters << current
131
+ elsif end_delimiter?(current) and delimiters[-1] != "\"" and current == opposite_delimiter_of(delimiters[-1])
132
+ delimiters.pop
133
+ elsif current == "\"" and delimiters[-1] == "\"" and idx > 0 and serialized[idx-1] != "\\"
134
+ delimiters.pop
135
+ elsif current == "\"" and delimiters[-1] != "\""
136
+ delimiters << current
137
+ end
138
+ end
139
+ return serialized.length
140
+ end
141
+
142
+ def start_delimiter?(c)
143
+ ["(", "[", "{", "<"].include? c
144
+ end
145
+
146
+ def end_delimiter?(c)
147
+ [")", "]", "}", ">"].include? c
148
+ end
149
+
150
+ def opposite_delimiter_of(c)
151
+ case c
152
+ when "[" then return "]"
153
+ when "{" then return "}"
154
+ when "(" then return ")"
155
+ when "<" then return ">"
156
+ else return "\""
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,83 @@
1
+ module OrientdbBinary
2
+ module Parser
3
+ class Serializer
4
+ def initialize()
5
+ end
6
+
7
+ def serialize_field_value(value)
8
+
9
+ if value.is_a? String
10
+ val = /^#\-{0,1}[\d]+:\-{0,1}[\d]+$/.match(value)
11
+ return value if val
12
+ value = value.sub(/\\/, "\\\\")
13
+ value = value.gsub(/"/, "\\\"")
14
+ return "\"#{value}\""
15
+ end
16
+
17
+ if value.is_a? Integer
18
+ return value.to_s
19
+ end
20
+
21
+ if value.is_a? Float
22
+ return value.to_s + "f"
23
+ end
24
+
25
+ if value.is_a? Bignum
26
+ return value.to_s + "l"
27
+ end
28
+
29
+ if value.is_a? BigDecimal
30
+ return value.to_s + "d"
31
+ end
32
+
33
+ if value.is_a? Array or value.is_a? Set
34
+ type = value.class.to_s.downcase == "set" ? "<$>" : "[$]"
35
+ result = []
36
+
37
+ value.each do |el|
38
+ result << serialize_field_value(el)
39
+ end
40
+ return type.gsub("$", result.join(','))
41
+ end
42
+
43
+ if value.is_a?(TrueClass) or value.is_a?(FalseClass)
44
+ return value.to_s
45
+ end
46
+
47
+ if value.is_a? Hash
48
+ type = value[:@type] == "d" ? "($)" : "{$}"
49
+ return type.gsub("$", serialize_document(value, value[:@type] != "d"))
50
+ end
51
+
52
+ if value.is_a? Date
53
+ value.to_datetime.to_time.to_i + "a"
54
+ end
55
+
56
+ if value.is_a? DateTime
57
+ value.to_time.to_i + "t"
58
+ end
59
+
60
+ if value.is_a? Time
61
+ value.to_i + "t"
62
+ end
63
+ end
64
+
65
+ def serialize_document(document, is_map=false)
66
+ klass = ""
67
+ result = []
68
+ document.each do |key, value|
69
+ unless [:@version, :@rid, :@type, :@cluster].include? key
70
+ if key == :@class
71
+ klass = value
72
+ else
73
+ field_wrap = is_map ? "\"" : ""
74
+ result << "#{key.to_s}:#{serialize_field_value(value)}"
75
+ end
76
+ end
77
+ end
78
+ return klass.empty? ? result.join(',') : klass + "@" + result.join(',')
79
+ end
80
+ end
81
+ end
82
+ end
83
+