massive_record 0.1.1 → 0.2.0.beta
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.
- 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
|