orientdb-binary 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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
+