massive_record 0.1.1 → 0.2.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +28 -5
- data/Gemfile.lock +12 -12
- data/README.md +29 -1
- data/lib/massive_record/adapters/initialize.rb +18 -0
- data/lib/massive_record/adapters/thrift/adapter.rb +25 -0
- data/lib/massive_record/adapters/thrift/column_family.rb +24 -0
- data/lib/massive_record/adapters/thrift/connection.rb +73 -0
- data/lib/massive_record/{thrift → adapters/thrift/hbase}/hbase.rb +0 -0
- data/lib/massive_record/{thrift → adapters/thrift/hbase}/hbase_constants.rb +0 -0
- data/lib/massive_record/{thrift → adapters/thrift/hbase}/hbase_types.rb +0 -0
- data/lib/massive_record/adapters/thrift/row.rb +150 -0
- data/lib/massive_record/adapters/thrift/scanner.rb +59 -0
- data/lib/massive_record/adapters/thrift/table.rb +169 -0
- data/lib/massive_record/orm/attribute_methods/read.rb +2 -1
- data/lib/massive_record/orm/base.rb +61 -3
- data/lib/massive_record/orm/coders/chained.rb +71 -0
- data/lib/massive_record/orm/coders/json.rb +17 -0
- data/lib/massive_record/orm/coders/yaml.rb +15 -0
- data/lib/massive_record/orm/coders.rb +3 -0
- data/lib/massive_record/orm/errors.rb +15 -2
- data/lib/massive_record/orm/finders/scope.rb +166 -0
- data/lib/massive_record/orm/finders.rb +45 -24
- data/lib/massive_record/orm/persistence.rb +4 -4
- data/lib/massive_record/orm/relations/interface.rb +170 -0
- data/lib/massive_record/orm/relations/metadata.rb +150 -0
- data/lib/massive_record/orm/relations/proxy/references_many.rb +229 -0
- data/lib/massive_record/orm/relations/proxy/references_one.rb +40 -0
- data/lib/massive_record/orm/relations/proxy/references_one_polymorphic.rb +49 -0
- data/lib/massive_record/orm/relations/proxy.rb +174 -0
- data/lib/massive_record/orm/relations.rb +6 -0
- data/lib/massive_record/orm/schema/column_interface.rb +1 -1
- data/lib/massive_record/orm/schema/field.rb +62 -27
- data/lib/massive_record/orm/single_table_inheritance.rb +21 -0
- data/lib/massive_record/version.rb +1 -1
- data/lib/massive_record/wrapper/adapter.rb +6 -0
- data/lib/massive_record/wrapper/base.rb +6 -7
- data/lib/massive_record/wrapper/cell.rb +9 -32
- data/lib/massive_record/wrapper/column_families_collection.rb +2 -2
- data/lib/massive_record/wrapper/errors.rb +10 -0
- data/lib/massive_record/wrapper/tables_collection.rb +1 -1
- data/lib/massive_record.rb +5 -12
- data/spec/orm/cases/attribute_methods_spec.rb +5 -1
- data/spec/orm/cases/base_spec.rb +77 -4
- data/spec/orm/cases/column_spec.rb +1 -1
- data/spec/orm/cases/finder_default_scope.rb +53 -0
- data/spec/orm/cases/finder_scope_spec.rb +288 -0
- data/spec/orm/cases/finders_spec.rb +56 -13
- data/spec/orm/cases/persistence_spec.rb +20 -5
- data/spec/orm/cases/single_table_inheritance_spec.rb +26 -0
- data/spec/orm/cases/table_spec.rb +1 -1
- data/spec/orm/cases/timestamps_spec.rb +16 -16
- data/spec/orm/coders/chained_spec.rb +73 -0
- data/spec/orm/coders/json_spec.rb +6 -0
- data/spec/orm/coders/yaml_spec.rb +6 -0
- data/spec/orm/models/best_friend.rb +7 -0
- data/spec/orm/models/friend.rb +4 -0
- data/spec/orm/models/person.rb +20 -6
- data/spec/orm/models/{person_with_timestamps.rb → person_with_timestamp.rb} +1 -1
- data/spec/orm/models/test_class.rb +3 -0
- data/spec/orm/relations/interface_spec.rb +207 -0
- data/spec/orm/relations/metadata_spec.rb +202 -0
- data/spec/orm/relations/proxy/references_many_spec.rb +624 -0
- data/spec/orm/relations/proxy/references_one_polymorphic_spec.rb +106 -0
- data/spec/orm/relations/proxy/references_one_spec.rb +111 -0
- data/spec/orm/relations/proxy_spec.rb +13 -0
- data/spec/orm/schema/field_spec.rb +101 -2
- data/spec/shared/orm/coders/an_orm_coder.rb +14 -0
- data/spec/shared/orm/relations/proxy.rb +154 -0
- data/spec/shared/orm/relations/singular_proxy.rb +68 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/thrift/cases/encoding_spec.rb +28 -7
- data/spec/wrapper/cases/adapter_spec.rb +9 -0
- data/spec/wrapper/cases/connection_spec.rb +13 -10
- data/spec/wrapper/cases/table_spec.rb +85 -85
- metadata +74 -22
- data/TODO.md +0 -8
- data/lib/massive_record/exceptions.rb +0 -11
- data/lib/massive_record/wrapper/column_family.rb +0 -22
- data/lib/massive_record/wrapper/connection.rb +0 -71
- data/lib/massive_record/wrapper/row.rb +0 -173
- data/lib/massive_record/wrapper/scanner.rb +0 -61
- data/lib/massive_record/wrapper/table.rb +0 -149
- data/spec/orm/cases/hbase/connection_spec.rb +0 -13
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,34 @@
|
|
1
1
|
# v0.2.0 (git develop)
|
2
2
|
|
3
3
|
|
4
|
-
# v0.
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
# v0.2.0.beta (git master)
|
5
|
+
|
6
|
+
- ORM will now take care of serialize and de-serialize of attributes like arrays, hashes etc. It is doing so
|
7
|
+
based on the type of your fields. You can select either JSON or YAML serialization for your data. As a default it
|
8
|
+
will use JSON. You can also, by chaining multiple coders together add support for multiple serialization types
|
9
|
+
when reading data from the database.
|
10
|
+
- Thrift-adapter will no longer auto-serialize objects likes hashes and arrays. Its vlaues must now be strings, and it
|
11
|
+
will only take care of encoding/decoding it to and from what Thrift expects (binary encoding).
|
12
|
+
- Compare Person === proxy_targeting_a_person will now be true. Makes case-when-constructions doable.
|
13
|
+
- Single table inheritance is supported. By default you can have an attribute called type to give you support for it in a table.
|
14
|
+
- A default_scope is possible to set on classes. For instance: Calling default_scope select(:only_this_column_family)
|
15
|
+
inside of a class will execute finder operations with this as default scope. If you need to fetch records of class
|
16
|
+
without your preset default scope you can use Model.unscoped.
|
17
|
+
- We now have some ActiveRecord like chaining of method calls when we do find-operations. Like Person.select(:column_family).limit(2)
|
18
|
+
is the same as Person.all(:select => ['column_family', :limit => 2])
|
19
|
+
- references_many has first() and limit() which uses the target array if loaded, or load only what it needs from the database.
|
20
|
+
- Wrapper::Thrift has been moved into Adapter::Thrift. Adding more adapters should be not that hard now.
|
21
|
+
- References many is now possible. We have to strategies: Store an array of foreign keys in the proxy_owner,
|
22
|
+
or supply a ids-starts-with and open up a scanner and read from that point.
|
23
|
+
- Setting a non-parsable value on date/time field will no longer raise an error.
|
24
|
+
- Scanner no longer fetches with a limit of 10 by default. It is set to 100000000.
|
25
|
+
- References one relations support polymorphic relations.
|
26
|
+
- Simple implementation of references_one relation. This is where you have a foreign key you will look up in a different table.
|
27
|
+
|
28
|
+
|
29
|
+
# v0.1.2
|
30
|
+
- Fixed, or at least made better, the is_yaml? method in Wrapper::Cell.This functionality of serialize/de-serialize
|
31
|
+
should be moved up into the ORM asap, but for now a hot fix has been applied.
|
8
32
|
|
9
33
|
|
10
34
|
# v0.1.1
|
@@ -18,7 +42,6 @@
|
|
18
42
|
- Bugfix: Database cleaner no longer tries to remove tables with same name twice.
|
19
43
|
|
20
44
|
|
21
|
-
|
22
45
|
# v0.1.0
|
23
46
|
|
24
47
|
- Communication with Hbase via Thrift.
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
massive_record (0.
|
4
|
+
massive_record (0.2.0.beta)
|
5
5
|
activemodel
|
6
6
|
activesupport
|
7
7
|
thrift (>= 0.5.0)
|
@@ -9,23 +9,23 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: http://rubygems.org/
|
11
11
|
specs:
|
12
|
-
activemodel (3.0.
|
13
|
-
activesupport (= 3.0.
|
12
|
+
activemodel (3.0.5)
|
13
|
+
activesupport (= 3.0.5)
|
14
14
|
builder (~> 2.1.2)
|
15
15
|
i18n (~> 0.4)
|
16
|
-
activesupport (3.0.
|
16
|
+
activesupport (3.0.5)
|
17
17
|
builder (2.1.2)
|
18
18
|
diff-lcs (1.1.2)
|
19
19
|
i18n (0.5.0)
|
20
|
-
rspec (2.
|
21
|
-
rspec-core (~> 2.
|
22
|
-
rspec-expectations (~> 2.
|
23
|
-
rspec-mocks (~> 2.
|
24
|
-
rspec-core (2.
|
25
|
-
rspec-expectations (2.
|
20
|
+
rspec (2.5.0)
|
21
|
+
rspec-core (~> 2.5.0)
|
22
|
+
rspec-expectations (~> 2.5.0)
|
23
|
+
rspec-mocks (~> 2.5.0)
|
24
|
+
rspec-core (2.5.1)
|
25
|
+
rspec-expectations (2.5.0)
|
26
26
|
diff-lcs (~> 1.1.2)
|
27
|
-
rspec-mocks (2.
|
28
|
-
thrift (0.
|
27
|
+
rspec-mocks (2.5.0)
|
28
|
+
thrift (0.6.0)
|
29
29
|
|
30
30
|
PLATFORMS
|
31
31
|
ruby
|
data/README.md
CHANGED
@@ -54,6 +54,8 @@ Both MassiveRecord::ORM::Table and MassiveRecord::ORM::Column do now have some f
|
|
54
54
|
- Casting of attributes
|
55
55
|
- Serialization of array / hashes
|
56
56
|
- Timestamps like created_at and updated_at. Updated at will always be available, created_at must be defined. See example down:
|
57
|
+
- Finder scopes. Like: Person.select(:only_columns_from_this_family).limit(10).collect(&:name)
|
58
|
+
- Ability to set a default scope.
|
57
59
|
|
58
60
|
Tables also have:
|
59
61
|
- Persistencey method calls like create, save and destroy (but they do not actually save things to hbase)
|
@@ -63,11 +65,19 @@ Tables also have:
|
|
63
65
|
- Save / update methods
|
64
66
|
- Auto-creation of table and column families on save if table does not exists.
|
65
67
|
- Destroy records
|
68
|
+
- Relations: See MassiveRecord::ORM::Relations::Interface ClassMethods for documentation
|
66
69
|
|
67
70
|
|
68
71
|
Here is an example of usage, both for Table and Column:
|
69
72
|
|
70
73
|
class Person < MassiveRecord::ORM::Table
|
74
|
+
references_one :boss, :class_name => "Person", :store_in => :info
|
75
|
+
references_one :attachment, :polymorphic => true
|
76
|
+
references_many :friends, :store_in => :info
|
77
|
+
references_many :cars, :records_starts_from => :cars_start_id
|
78
|
+
|
79
|
+
default_scope select(:info)
|
80
|
+
|
71
81
|
column_family :info do
|
72
82
|
field :name
|
73
83
|
field :email
|
@@ -75,12 +85,29 @@ Here is an example of usage, both for Table and Column:
|
|
75
85
|
field :points, :integer, :default => 0
|
76
86
|
field :date_of_birth, :date
|
77
87
|
field :newsletter, :boolean, :default => false
|
88
|
+
field :type # Used for single table inheritance
|
78
89
|
|
79
90
|
timestamps # ..or field :created_at, :time
|
80
91
|
end
|
81
92
|
|
93
|
+
column_family :misc do
|
94
|
+
field :with_a_lot_of_uninteresting_data
|
95
|
+
end
|
96
|
+
|
97
|
+
|
82
98
|
validates_presence_of :name, :email
|
83
99
|
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
|
100
|
+
|
101
|
+
# Returns the id the scanner should start from in the Car table
|
102
|
+
# to fetch cars related to this person
|
103
|
+
def cars_start_id
|
104
|
+
id+'-'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class Friend < Person
|
109
|
+
# This one will be stored in Person's table with it's type set to Friend.
|
110
|
+
# Calling Person.all will return object back as a Friend.
|
84
111
|
end
|
85
112
|
|
86
113
|
|
@@ -148,7 +175,8 @@ You can, if you'd like, work directly against the adapter.
|
|
148
175
|
## Planned work
|
149
176
|
|
150
177
|
- Rename Wrapper to Adapter, and make it easy to switch from Thrift to another way of communicating with Hbase.
|
151
|
-
-
|
178
|
+
- Embedded objects.
|
179
|
+
- Cache the decoded values of attributes, not use the value_is_already_decoded?. This will fix possible problem with YAML as coder backend.
|
152
180
|
- Implement other Adapters, for instance using jruby and the Java API.
|
153
181
|
|
154
182
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MassiveRecord
|
2
|
+
def self.adapter=(name)
|
3
|
+
@adapter = name
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.adapter
|
7
|
+
@adapter
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Default adapter is set to thrift
|
12
|
+
MassiveRecord.adapter = :thrift
|
13
|
+
|
14
|
+
# Check the adapter is valid
|
15
|
+
raise "The adapter can only be 'thrift'." unless [:thrift].include?(MassiveRecord.adapter)
|
16
|
+
|
17
|
+
# Load specific adapter
|
18
|
+
require "massive_record/adapters/#{MassiveRecord.adapter}/adapter"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MassiveRecord
|
2
|
+
module Adapters
|
3
|
+
module Thrift
|
4
|
+
end
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
ADAPTER = MassiveRecord::Adapters::Thrift
|
9
|
+
|
10
|
+
# Thrift Gems
|
11
|
+
require 'thrift'
|
12
|
+
require 'thrift/transport/socket'
|
13
|
+
require 'thrift/protocol/binary_protocol'
|
14
|
+
|
15
|
+
# Generated Ruby classes from Thrift for HBase
|
16
|
+
require 'massive_record/adapters/thrift/hbase/hbase_constants'
|
17
|
+
require 'massive_record/adapters/thrift/hbase/hbase_types'
|
18
|
+
require 'massive_record/adapters/thrift/hbase/hbase'
|
19
|
+
|
20
|
+
# Adapter
|
21
|
+
require 'massive_record/adapters/thrift/column_family'
|
22
|
+
require 'massive_record/adapters/thrift/connection'
|
23
|
+
require 'massive_record/adapters/thrift/row'
|
24
|
+
require 'massive_record/adapters/thrift/scanner'
|
25
|
+
require 'massive_record/adapters/thrift/table'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module MassiveRecord
|
2
|
+
module Adapters
|
3
|
+
module Thrift
|
4
|
+
class ColumnFamily
|
5
|
+
|
6
|
+
attr_accessor :name, :max_versions, :columns
|
7
|
+
|
8
|
+
def initialize(column_name, opts = {})
|
9
|
+
@name = column_name
|
10
|
+
@max_versions = opts[:max_versions] || 10
|
11
|
+
@columns = opts[:columns] || []
|
12
|
+
end
|
13
|
+
|
14
|
+
def descriptor
|
15
|
+
Apache::Hadoop::Hbase::Thrift::ColumnDescriptor.new do |col|
|
16
|
+
col.name = "#{name}:"
|
17
|
+
col.maxVersions = max_versions
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module MassiveRecord
|
2
|
+
module Adapters
|
3
|
+
module Thrift
|
4
|
+
class Connection
|
5
|
+
|
6
|
+
attr_accessor :host, :port, :timeout
|
7
|
+
|
8
|
+
def initialize(opts = {})
|
9
|
+
@timeout = 4000
|
10
|
+
@host = opts[:host]
|
11
|
+
@port = opts[:port] || 9090
|
12
|
+
end
|
13
|
+
|
14
|
+
def transport
|
15
|
+
@transport ||= ::Thrift::BufferedTransport.new(::Thrift::Socket.new(@host, @port, @timeout))
|
16
|
+
end
|
17
|
+
|
18
|
+
def open
|
19
|
+
protocol = ::Thrift::BinaryProtocol.new(transport)
|
20
|
+
@client = Apache::Hadoop::Hbase::Thrift::Hbase::Client.new(protocol)
|
21
|
+
|
22
|
+
begin
|
23
|
+
transport.open()
|
24
|
+
true
|
25
|
+
rescue
|
26
|
+
raise MassiveRecord::Wrapper::Errors::ConnectionException.new, "Unable to connect to HBase on #{@host}, port #{@port}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def close
|
31
|
+
@transport.close.nil?
|
32
|
+
end
|
33
|
+
|
34
|
+
def client
|
35
|
+
@client
|
36
|
+
end
|
37
|
+
|
38
|
+
def open?
|
39
|
+
@transport.try("open?")
|
40
|
+
end
|
41
|
+
|
42
|
+
def tables
|
43
|
+
collection = MassiveRecord::Wrapper::TablesCollection.new
|
44
|
+
collection.connection = self
|
45
|
+
getTableNames().each{|table_name| collection.push(table_name)}
|
46
|
+
collection
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_table(table_name)
|
50
|
+
MassiveRecord::Wrapper::Table.new(self, table_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Wrapp HBase API to be able to catch errors and try reconnect
|
54
|
+
def method_missing(method, *args)
|
55
|
+
begin
|
56
|
+
open if not @client
|
57
|
+
client.send(method, *args) if @client
|
58
|
+
rescue IOError
|
59
|
+
@client = nil
|
60
|
+
open
|
61
|
+
client.send(method, *args) if @client
|
62
|
+
rescue ::Thrift::TransportException
|
63
|
+
@transport = nil
|
64
|
+
@client = nil
|
65
|
+
open
|
66
|
+
client.send(method, *args) if @client
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module MassiveRecord
|
2
|
+
module Adapters
|
3
|
+
module Thrift
|
4
|
+
class Row
|
5
|
+
|
6
|
+
attr_accessor :id, :column_families, :columns, :new_record, :table
|
7
|
+
|
8
|
+
def initialize(opts = {})
|
9
|
+
@id = opts[:id]
|
10
|
+
self.values = opts[:values] || {}
|
11
|
+
@table = opts[:table]
|
12
|
+
@column_families = opts[:column_families] || []
|
13
|
+
@columns = opts[:columns] || {}
|
14
|
+
@new_record = true
|
15
|
+
end
|
16
|
+
|
17
|
+
def column_names
|
18
|
+
columns.keys
|
19
|
+
end
|
20
|
+
|
21
|
+
def fetch_all_column_families
|
22
|
+
@table.fetch_column_family
|
23
|
+
fetch_column_families(@table.column_family_names)
|
24
|
+
end
|
25
|
+
|
26
|
+
def fetch_column_families(list)
|
27
|
+
@column_families = table.column_families.collect do |column_name, description|
|
28
|
+
MassiveRecord::Wrapper::ColumnFamily.new(column_name.split(":").first, {
|
29
|
+
:row => self,
|
30
|
+
:name => description.name,
|
31
|
+
:max_versions => description.maxVersions,
|
32
|
+
:compression => description.compression,
|
33
|
+
:in_memory => description.inMemory
|
34
|
+
# bloomFilterType, bloomFilterVectorSize, bloomFilterNbHashes, blockCacheEnabled, timeToLive
|
35
|
+
})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# = Parse columns / cells and create a Hash from them
|
40
|
+
def values
|
41
|
+
@columns.inject({"id" => id}) {|h, (column_name, cell)| h[column_name] = cell.value; h}
|
42
|
+
end
|
43
|
+
|
44
|
+
def values=(data)
|
45
|
+
@values = {}
|
46
|
+
update_columns(data)
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_columns(data = {})
|
50
|
+
data.each do |column_family_name, columns|
|
51
|
+
columns.each do |column_name, values|
|
52
|
+
update_column(column_family_name, column_name, values)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_column(column_family_name, column_name, value)
|
58
|
+
column = "#{column_family_name}:#{column_name}"
|
59
|
+
|
60
|
+
if @columns[column].nil?
|
61
|
+
@columns[column] = MassiveRecord::Wrapper::Cell.new({:value => value, :created_at => Time.now})
|
62
|
+
else
|
63
|
+
@columns[column].value = value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# = Parse columns cells and save them
|
68
|
+
def save
|
69
|
+
mutations = []
|
70
|
+
|
71
|
+
@columns.each do |column_name, cell|
|
72
|
+
m = Apache::Hadoop::Hbase::Thrift::Mutation.new
|
73
|
+
m.column = column_name
|
74
|
+
m.value = cell.value_to_thrift
|
75
|
+
|
76
|
+
mutations.push(m)
|
77
|
+
end
|
78
|
+
|
79
|
+
@table.client.mutateRow(@table.name, id.to_s, mutations).nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
#
|
84
|
+
# FIXME
|
85
|
+
#
|
86
|
+
# The thrift wrapper is only working with strings as far as I can see,
|
87
|
+
# and the atomicIncrement call on strings kinda doesn't make sense on strings
|
88
|
+
#
|
89
|
+
# For now I'll implement this without atomicIncrement, to get the behaviour we want.
|
90
|
+
# Guess this in time will either be fixed or raised an not-supported-error. If the
|
91
|
+
# latter is the case I guess we'll need to shift over to a jruby adapter and use the
|
92
|
+
# java api instead of thrift.
|
93
|
+
#
|
94
|
+
def atomic_increment(column_name, by = 1)
|
95
|
+
# @table.client.atomicIncrement(@table.name, id.to_s, column_name, by)
|
96
|
+
value_to_increment = @columns[column_name.to_s].value
|
97
|
+
|
98
|
+
raise "Value to increment (#{value_to_increment}) doesnt seem to be a number!" unless value_to_increment =~ /^\d+$/
|
99
|
+
raise "Argument by must be an integer" unless by.is_a? Fixnum
|
100
|
+
|
101
|
+
value_to_increment = value_to_increment.to_i
|
102
|
+
value_to_increment += by
|
103
|
+
value_to_increment = value_to_increment.to_s
|
104
|
+
|
105
|
+
mutation = Apache::Hadoop::Hbase::Thrift::Mutation.new
|
106
|
+
mutation.column = column_name
|
107
|
+
mutation.value = value_to_increment
|
108
|
+
|
109
|
+
if @table.client.mutateRow(@table.name, id.to_s, [mutation]).nil?
|
110
|
+
value_to_increment
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.populate_from_trow_result(result, connection, table_name, column_families = [])
|
115
|
+
row = self.new
|
116
|
+
row.id = result.row
|
117
|
+
row.new_record = false
|
118
|
+
row.table = Table.new(connection, table_name)
|
119
|
+
row.column_families = column_families
|
120
|
+
|
121
|
+
result.columns.each do |name, value|
|
122
|
+
row.columns[name] = MassiveRecord::Wrapper::Cell.new({
|
123
|
+
:value => value.value,
|
124
|
+
:created_at => Time.at(value.timestamp / 1000, (value.timestamp % 1000) * 1000)
|
125
|
+
})
|
126
|
+
end
|
127
|
+
|
128
|
+
row
|
129
|
+
end
|
130
|
+
|
131
|
+
def destroy
|
132
|
+
@table.client.deleteAllRow(@table.name, @id).nil?
|
133
|
+
end
|
134
|
+
|
135
|
+
def new_record?
|
136
|
+
@new_record
|
137
|
+
end
|
138
|
+
|
139
|
+
def prev
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
def updated_at
|
144
|
+
columns.values.collect(&:created_at).max
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|