Class: BigRecord::Base

Inherits:
Model show all
Defined in:
lib/big_record/base.rb,
lib/big_record/connection_adapters/hbase_adapter.rb,
lib/big_record/connection_adapters/cassandra_adapter.rb,
lib/big_record/connection_adapters/hbase_rest_adapter.rb,
lib/big_record/connection_adapters/abstract/connection_specification.rb

Defined Under Namespace

Classes: ConnectionSpecification

Constant Summary

VALID_FIND_OPTIONS =
[:limit, :offset, :include, :view, :versions, :timestamp,
:include_deleted, :force_reload, :columns, :stop_row]
@@verification_timeout =
0
@@defined_connections =

The class -> [adapter_method, config] map

{}
@@active_connections =

The class -> thread id -> adapter cache. (class -> adapter if not allow_concurrency)

{}

Constants inherited from Model

ID_FIELD_SEPARATOR, ID_WHITE_SPACE_CHAR

Instance Attribute Summary

Class Method Summary

Instance Method Summary

Methods inherited from Model

#==, ===, #[]=, accessible_attributes, #all_attributes_loaded=, #all_attributes_loaded?, attr_accessible, attr_create_accessible, attr_protected, attr_readonly, #attribute_for_inspect, #attribute_names, #attribute_present?, #attributes, #attributes=, benchmark, column, #column_for_attribute, column_methods_hash, column_names, columns, columns_hash, content_columns, create_accessible_attributes, #deserialize, #eql?, #freeze, #frozen?, #has_attribute?, #hash, #human_attribute_name, human_attribute_name, #id, #id=, #inspect, instantiate, #preinitialize, protected_attributes, quote_value, #quoted_id, read_methods, #readonly!, #readonly?, readonly_attributes, #reload, reset_subclasses, #respond_to?, #safe_attributes=, silence, store_primary_key?, #to_s, undecorated_table_name

Constructor Details

- (Base) initialize(attrs = nil)

New objects can be instantiated as either empty (pass no construction parameter) or pre-set with attributes but not yet saved (pass a hash with key names matching the associated table column names). In both instances, valid attribute keys are determined by the column names of the associated table — hence you can’t have attributes that aren’t part of the table columns.



18
19
20
21
22
# File 'lib/big_record/base.rb', line 18

def initialize(attrs = nil)
  @new_record = true
  super
  attrs.keys.each{ |k| set_loaded(k) } if attrs
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class BigRecord::Model

Instance Attribute Details

- (Object) modified_attributes

Returns the value of attribute modified_attributes



5
6
7
# File 'lib/big_record/base.rb', line 5

def modified_attributes
  @modified_attributes
end

Class Method Details

+ (Object) active_connection_name

:nodoc:



54
55
56
57
58
59
60
61
62
63
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 54

def active_connection_name 
  @active_connection_name ||=
     if active_connections[name] || @@defined_connections[name]
       name
     elsif self == BigRecord::Base
       nil
     else
       superclass.active_connection_name
     end
end

+ (Object) allow_concurrency=(threaded)

set concurrency support flag (not thread safe, like most of the methods in this file)



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 41

def allow_concurrency=(threaded) #:nodoc:
  logger.debug "allow_concurrency=#{threaded}" if logger
  return if @@allow_concurrency == threaded
  clear_all_cached_connections!
  @@allow_concurrency = threaded
  method_prefix = threaded ? "thread_safe" : "single_threaded"
  sing = (class << self; self; end)
  [:active_connections, :scoped_methods].each do |method|
    sing.send(:alias_method, method, "#{method_prefix}_#{method}")
  end
  log_connections if logger
end

+ (Class) base_class

The base class which inherits BigRecord::Base directly.

Returns:

  • (Class)

    The base class which inherits BigRecord::Base directly.



413
414
415
# File 'lib/big_record/base.rb', line 413

def base_class
  (superclass == BigRecord::Base) ? self : superclass.base_class
end

+ (Object) cassandra_connection(config)

:nodoc:



3
4
5
6
7
8
9
10
11
12
13
14
15
# File 'lib/big_record/connection_adapters/cassandra_adapter.rb', line 3

def self.cassandra_connection(config) # :nodoc:
  begin
    require 'cassandra'
  rescue LoadError => e
    puts "[BigRecord] The 'cassandra' gem is needed for CassandraAdapter. Install it with: gem install cassandra"
    raise e
  end

  config = config.symbolize_keys
  
  client = Cassandra.new(config[:keyspace], config[:servers])
  ConnectionAdapters::CassandraAdapter.new(client, logger, [], config)
end

+ (Object) clear_active_connection_name

:nodoc:



65
66
67
68
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 65

def clear_active_connection_name 
  @active_connection_name = nil
  subclasses.each { |klass| klass.clear_active_connection_name }
end

+ (Object) clear_active_connections!

Clears the cache which maps classes to connections.



84
85
86
87
88
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 84

def clear_active_connections!
  clear_cache!(@@active_connections) do |name, conn|
    conn.disconnect!
  end
end

+ (Object) clear_reloadable_connections!

Clears the cache which maps classes



91
92
93
94
95
96
97
98
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 91

def clear_reloadable_connections!
  @@active_connections.each do |name, conn|
    if conn.requires_reloading?
      conn.disconnect!
      @@active_connections.delete(name)
    end
  end
end

+ (Object) columns_to_find(options = {})

Return the list of fully qualified column names, i.e. ["family:qualifier"].

Returns the column names based on the options argument in order of :columns,then :view, i.e. disregards :view if :columns is defined.

Options Hash (options):

  • (Array<String, Symbol>) :columns N/A

    List of fully qualified column names or column aliases.

  • (String, Symbol) :view N/A

    The name of the view as defined with view.



484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/big_record/base.rb', line 484

def columns_to_find(options={})
  c =
    if options[:columns]
      column_list = []
      options[:columns].each do |column_name|
        # If the column name provided is a full name, i.e. includes column family and qualifier,
        # then add it to the list.
        if column_name.to_s =~ /:/
          column_list << column_name

        # Otherwise, it's probably an alias and we need to check that.
        else
          columns.select{|column| column_list << column.name if column.alias == column_name.to_s}
        end
      end
      column_list
    elsif options[:view]
      raise ArgumentError, "Unknown view: #{options[:view]}" unless views_hash[options[:view]]
      if options[:view] == :all
        ["#{default_family}:"]
      else
        views_hash[options[:view]].column_names
      end
    elsif views_hash[:default]
      views_hash[:default].column_names
    else
      ["#{default_family}:"]
    end
  c += [options[:include]] if options[:include]
  c.flatten.reject{|x| x == "id"}
end

+ (Boolean) connected?

Returns true if a connection that’s accessible to this class have already been opened.

Returns:

  • (Boolean)


239
240
241
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 239

def self.connected?
  active_connections[active_connection_name] ? true : false
end

+ (Object) connection

Returns the connection currently associated with the class. This can also be used to "borrow" the connection to do database work unrelated to any of the specific Active Records.



73
74
75
76
77
78
79
80
81
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 73

def connection
  if @active_connection_name && (conn = active_connections[@active_connection_name])
    conn
  else
    # retrieve_connection sets the cache key.
    conn = retrieve_connection
    active_connections[@active_connection_name] = conn
  end
end

+ (Object) connection=(spec)

Set the connection for the class.



257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 257

def self.connection=(spec) #:nodoc:
  if spec.kind_of?(BigRecord::ConnectionAdapters::AbstractAdapter)
    active_connections[name] = spec
  elsif spec.kind_of?(ConnectionSpecification)
    config = spec.config.reverse_merge(:allow_concurrency => @@allow_concurrency)
    self.connection = self.send(spec.adapter_method, config)
  elsif spec.nil?
    raise ConnectionNotEstablished
  else
    establish_connection spec
  end
end

+ (Object) create(attrs = nil)

Creates an object, instantly saves it as a record (if the validation permits it), and returns it. If the save fails under validations, the unsaved object is still returned.



310
311
312
313
314
315
316
317
318
# File 'lib/big_record/base.rb', line 310

def create(attrs = nil)
  if attrs.is_a?(Array)
    attrs.collect { |attr| create(attr) }
  else
    object = new(attrs)
    object.save
    object
  end
end

+ (Object) default_column_prefix



468
469
470
# File 'lib/big_record/base.rb', line 468

def default_column_prefix
  "#{default_family}:"
end

+ (Object) default_columns

Default columns to create with the model, such as primary key.



464
465
466
# File 'lib/big_record/base.rb', line 464

def default_columns
  {primary_key => ConnectionAdapters::Column.new(primary_key, 'string')}
end

+ (Object) default_family

Get the default column family used to store attributes that have no column family set explicitly.

Defaults to "attribute"



400
401
402
# File 'lib/big_record/base.rb', line 400

def default_family
  @default_family ||= "attribute"
end

+ (Object) default_views

Return the hash of default views which consist of all columns and the :default named views.



473
474
475
# File 'lib/big_record/base.rb', line 473

def default_views
  {:all=>ConnectionAdapters::View.new('all', nil, self), :default=>ConnectionAdapters::View.new('default', nil, self)}
end

+ (Object) delete(id)

Deletes the record with the given id without instantiating an object first. If an array of ids is provided, all of them are deleted.



345
346
347
348
349
350
351
# File 'lib/big_record/base.rb', line 345

def delete(id)
  if id.is_a?(Array)
    id.each { |a| connection.delete(table_name, a) }
  else
    connection.delete(table_name, id)
  end
end

+ (Object) delete_all(conditions = nil)

TODO:

take into consideration the conditions

Deletes all the records that match the condition without instantiating the objects first (and hence not calling the destroy method). Example:

  Post.delete_all "person_id = 5 AND (category = 'Something' OR category = 'Else')"


378
379
380
381
382
# File 'lib/big_record/base.rb', line 378

def delete_all(conditions = nil)
  connection.get_consecutive_rows(table_name, nil, nil, ["#{default_family}:"]).each do |row|
    connection.delete(table_name, row["id"])
  end
end

+ (Object) destroy(id)

Destroys the record with the given id by instantiating the object and calling #destroy (all the callbacks are the triggered). If an array of ids is provided, all of them are destroyed.



355
356
357
# File 'lib/big_record/base.rb', line 355

def destroy(id)
  id.is_a?(Array) ? id.each { |a| destroy(a) } : find(id).destroy
end

+ (Object) destroy_all(conditions = nil)

Destroys the objects for all the records that match the condition by instantiating each object and calling the destroy method. Example:

  Person.destroy_all "last_login < '2004-04-04'"


369
370
371
# File 'lib/big_record/base.rb', line 369

def destroy_all(conditions = nil)
  find(:all, :conditions => conditions).each { |object| object.destroy }
end

+ (Object) establish_connection(spec = nil)

Establishes the connection to the database. Accepts a hash as input where the :adapter key must be specified with the name of a database adapter (in lower-case) example for regular databases (MySQL, Postgresql, etc):

  ActiveRecord::Base.establish_connection(
    :adapter  => "mysql",
    :host     => "localhost",
    :username => "myuser",
    :password => "mypass",
    :database => "somedatabase"
  )

Example for SQLite database:

  ActiveRecord::Base.establish_connection(
    :adapter => "sqlite",
    :database  => "path/to/dbfile"
  )

Also accepts keys as strings (for parsing from yaml for example):

  ActiveRecord::Base.establish_connection(
    "adapter" => "sqlite",
    "database"  => "path/to/dbfile"
  )

The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError may be returned on an error.



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 191

def self.establish_connection(spec = nil)
  case spec
    when nil
      raise AdapterNotSpecified unless defined? RAILS_ENV
      establish_connection(RAILS_ENV)
    when ConnectionSpecification
      clear_active_connection_name
      @active_connection_name = name
      @@defined_connections[name] = spec
    when Symbol, String
      if configuration = configurations[spec.to_s]
        establish_connection(configuration)
      else
        raise AdapterNotSpecified, "#{spec} database is not configured"
      end
    else
      spec = spec.symbolize_keys
      unless spec.key?(:adapter) then raise AdapterNotSpecified, "database configuration does not specify adapter" end
      adapter_method = "#{spec[:adapter]}_connection"
      unless respond_to?(adapter_method) then raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter" end
      remove_connection
      establish_connection(ConnectionSpecification.new(spec, adapter_method))
  end
end

+ (Boolean) exists?(id)

Returns true if the given id represents the primary key of a record in the database, false otherwise.

Returns:

  • (Boolean)


302
303
304
305
306
# File 'lib/big_record/base.rb', line 302

def exists?(id)
  !find(id).nil?
rescue BigRecord::BigRecordError
  false
end

+ (Object) families

Return the list of families for this class



239
240
241
# File 'lib/big_record/base.rb', line 239

def families
  columns.collect(&:family).uniq
end

+ (Object) find(*args)



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/big_record/base.rb', line 283

def find(*args)
  options = extract_options_from_args!(args)
  validate_find_options(options)

  # set a default view
  if options[:view]
    options[:view] = options[:view].to_sym
  else
    options[:view] = :default
  end

  case args.first
    when :first then find_every(options.merge({:limit => 1})).first
    when :all   then find_every(options)
    else             find_from_ids(args, options)
  end
end

+ (Object) hbase_connection(config)

Establishes a connection to the database that’s used by all Active Record objects.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/big_record/connection_adapters/hbase_adapter.rb', line 7

def self.hbase_connection(config)
  begin
    require 'big_record_driver'
  rescue LoadError => e
    puts "[BigRecord] bigrecord-driver is needed for HbaseAdapter. Install it with: gem install bigrecord-driver"
    raise e
  end

  config = config.symbolize_keys

  zookeeper_host          = config[:zookeeper_host]
  zookeeper_client_port   = config[:zookeeper_client_port]
  drb_host                = config[:drb_host]
  drb_port                = config[:drb_port]

  hbase = BigRecord::Driver::Client.new(config)

  ConnectionAdapters::HbaseAdapter.new(hbase, logger, [zookeeper_host, zookeeper_client_port], config)
end

+ (Object) hbase_rest_connection(config)

Establishes a connection to the database that’s used by all Active Record objects.



6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/big_record/connection_adapters/hbase_rest_adapter.rb', line 6

def self.hbase_rest_connection(config) # :nodoc:
  begin
    require 'stargate'
  rescue LoadError => e
    puts "[BigRecord] hbase-stargate is needed for HbaseRestAdapter. Install it with: gem install hbase-stargate"
    raise e
  end

  config = config.symbolize_keys

  api_address = config[:api_address]
  hbase = Stargate::Client.new(api_address)
  ConnectionAdapters::HbaseRestAdapter.new(hbase, logger, [], config)
end

+ (Object) inherited(child)

:nodoc:



7
8
9
10
11
12
# File 'lib/big_record/base.rb', line 7

def self.inherited(child) #:nodoc:
  @@subclasses[self] ||= []
  @@subclasses[self] << child
  child.set_table_name child.name.tableize if child.superclass == BigRecord::Base
  super
end

+ (Object) log_connections

connection state logging



271
272
273
274
275
276
277
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 271

def self.log_connections 
  if logger
    logger.info "Defined connections: #{@@defined_connections.inspect}"
    logger.info "Active connections: #{active_connections.inspect}"
    logger.info "Active connection name: #{@active_connection_name}"
  end
end

+ (Object) primary_key

Return the name of the primary key. Defaults to "id".



234
235
236
# File 'lib/big_record/base.rb', line 234

def primary_key
  @primary_key ||= "id"
end

+ (Object) remove_connection(klass = self)

Remove the connection for this class. This will close the active connection and the defined connection (if they exist). The result can be used as argument for establish_connection, for easy re-establishing of the connection.



247
248
249
250
251
252
253
254
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 247

def self.remove_connection(klass=self)
  spec = @@defined_connections[klass.name]
  konn = active_connections[klass.name]
  @@defined_connections.delete_if { |key, value| value == spec }
  active_connections.delete_if { |key, value| value == konn }
  konn.disconnect! if konn
  spec.config if spec
end

+ (Object) retrieve_connection

Locate the connection of the nearest super class. This can be an active or defined connections: if it is the latter, it will be opened and set as the active connection for the class it was defined for (not necessarily the current class).



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 220

def self.retrieve_connection 
  # Name is nil if establish_connection hasn't been called for
  # some class along the inheritance chain up to AR::Base yet.
  if name = active_connection_name
    if conn = active_connections[name]
      # Verify the connection.
      conn.verify!(@@verification_timeout)
    elsif spec = @@defined_connections[name]
      # Activate this connection specification.
      klass = name.constantize
      klass.connection = spec
      conn = active_connections[name]
    end
  end

  conn or raise ConnectionNotEstablished
end

+ (Object) scan(options = {}, &code)

HBase scanner utility — scans the table and executes code on each record

Examples:

Entity.scan(:batch_size => 200) {|e|puts "#{e.name} is a child!" if e.parent}

Options Hash (options):

  • (Integer) :batch_size N/A
    • number of records to retrieve from database with each scan iteration.
  • (Block) :code N/A
    • the code to execute (see example above for syntax)


251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/big_record/base.rb', line 251

def scan(options={}, &code)
  options = options.dup
  limit = options.delete(:batch_size) || 100

  items_processed = 0

  # add an extra record for defining the next offset without duplicating records
  limit += 1
  last_row_id = nil

  while true
    items = find(:all, options.merge({:limit => limit}))

    # set the new offset as the extra record
    unless items.empty?
      items.delete_at(0) if items[0].id == last_row_id

      break if items.empty?

      last_row_id = items.last.id
      options[:offset] = last_row_id
      items_processed += items.size

      items.each do |item|
        code.call(item)
      end
    else
      break
    end
  end
end

+ (Object) set_default_family(name)

Set the default column family used to store attributes that have no column family set explicitly.

Examples:

set_default_family :attr  # instead of using :attribute as the default.


408
409
410
# File 'lib/big_record/base.rb', line 408

def set_default_family(name)
  @default_family = name.to_s
end

+ (Object) set_table_name(name)



393
394
395
# File 'lib/big_record/base.rb', line 393

def set_table_name(name)
  @table_name = name.to_s
end

+ (Object) single_threaded_active_connections

:nodoc:



29
30
31
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 29

def single_threaded_active_connections 
  @@active_connections
end

+ (Object) table_name



389
390
391
# File 'lib/big_record/base.rb', line 389

def table_name
  @table_name || superclass.table_name
end

+ (Object) thread_safe_active_connections Also known as: active_connections

Retrieve the connection cache.



25
26
27
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 25

def thread_safe_active_connections 
  @@active_connections[Thread.current.object_id] ||= {}
end

+ (Object) truncate

Truncate the table for this model



385
386
387
# File 'lib/big_record/base.rb', line 385

def truncate
  connection.truncate_table(table_name)
end

+ (Object) update(id, attributes)

Finds the record from the passed id, instantly saves it with the passed attributes (if the validation permits it), and returns it. If the save fails under validations, the unsaved object is still returned.

The arguments may also be given as arrays in which case the update method is called for each pair of id and attributes and an array of objects is returned.

Examples:

of updating one record:

Person.update(15, {:user_name => 'Samuel', :group => 'expert'})

of updating multiple records:

people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} }
Person.update(people.keys, people.values)


332
333
334
335
336
337
338
339
340
341
# File 'lib/big_record/base.rb', line 332

def update(id, attributes)
  if id.is_a?(Array)
    idx = -1
    id.collect { |a| idx += 1; update(a, attributes[idx]) }
  else
    object = find(id)
    object.update_attributes(attributes)
    object
  end
end

+ (Object) update_all(updates, conditions = nil)

Updates all records with the SET-part of an SQL update statement in updates and returns an integer with the number of rows updated. A subset of the records can be selected by specifying conditions. Example:

  Billing.update_all "category = 'authorized', approved = 1", "author = 'David'"

Raises:



362
363
364
# File 'lib/big_record/base.rb', line 362

def update_all(updates, conditions = nil)
  raise NotImplemented, "update_all"
end

+ (Object) verify_active_connections!

Verify active connections.



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 101

def verify_active_connections! 
  if @@allow_concurrency
    remove_stale_cached_threads!(@@active_connections) do |name, conn|
      conn.disconnect!
    end
  end

  active_connections.each_value do |connection|
    connection.verify!(@@verification_timeout)
  end
end

+ (Object) view(name, *columns)

Macro for defining a named view to a list of columns.

Examples:

view :front_page, :name, :title, :description
view :summary, ["attribute:name", "attribute:title"]

Parameters:

  • (String, Symbol) name

    Give it an arbitrary name.

  • (Array<String, Symbol>) columns

    List of columns to associate to this view. Can use column aliases or fully qualified names.



425
426
427
428
429
430
431
432
433
# File 'lib/big_record/base.rb', line 425

def view(name, *columns)
  name = name.to_sym
  @views_hash ||= default_views

  # The other variables that are cached and depend on @views_hash need to be reloaded
  invalidate_views

  @views_hash[name] = ConnectionAdapters::View.new(name, columns.flatten, self)
end

+ (Object) view_names

Get a list of view names defined by view.



441
442
443
# File 'lib/big_record/base.rb', line 441

def view_names
  @view_names ||= views_hash.keys
end

+ (Object) views

Get a list of all the views defined by the view macro for the model.



436
437
438
# File 'lib/big_record/base.rb', line 436

def views
  @views ||= views_hash.values
end

+ (Object) views_hash

Get the full hash of views consisting of the name as keys, and the ConnectionAdapters::View views.



446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
# File 'lib/big_record/base.rb', line 446

def views_hash
  unless @all_views_hash
    # add default hbase columns
    @all_views_hash =
      if self == BigRecord::Base # stop at Base
         @views_hash = default_views
      else
        if @views_hash
          superclass.views_hash.merge(default_views).merge(@views_hash)
        else
          superclass.views_hash.merge(default_views)
        end
      end
  end
  @all_views_hash
end

Instance Method Details

- (Object) [](attr_name)

Returns the value of the attribute identified by attr_name after it has been typecast (for example, "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)). (Alias for the protected read_attribute method).



27
28
29
30
31
32
33
# File 'lib/big_record/base.rb', line 27

def [](attr_name)
  if attr_name.ends_with?(":")
    read_family_attributes(attr_name)
  else
    read_attribute(attr_name)
  end
end

- (Object) connection

Returns the connection currently associated with the class. This can also be used to "borrow" the connection to do database work that isn’t easily done without going straight to SQL.



160
161
162
# File 'lib/big_record/connection_adapters/abstract/connection_specification.rb', line 160

def connection
  self.class.connection
end

- (Object) destroy

Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can’t be persisted).



162
163
164
165
166
167
168
169
170
# File 'lib/big_record/base.rb', line 162

def destroy
  unless new_record?
    connection.delete(self.class.table_name, self.id)
  end

  # FIXME: this currently doesn't work because we write the attributes everytime we read them
  # which means that we cannot read the attributes of a deleted record... it's bad
#      freeze
end

- (Boolean) is_loaded?(name)

Returns:

  • (Boolean)


137
138
139
140
# File 'lib/big_record/base.rb', line 137

def is_loaded?(name)
  @loaded_columns ||= []
  @loaded_columns.include?(name)
end

- (Boolean) new_record?

Returns true if this object hasn’t been saved yet — that is, a record for the object doesn’t exist yet.

Returns:

  • (Boolean)


144
145
146
# File 'lib/big_record/base.rb', line 144

def new_record?
  @new_record
end

- (Object) read_attribute(attr_name, options = {})

Returns the value of the attribute identified by attr_name after it has been typecast (for example, "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/big_record/base.rb', line 37

def read_attribute(attr_name, options={})
  attr_name = attr_name.to_s
  column = column_for_attribute(attr_name)
  if column
    # First check if the attribute is already in the attributes hash
    if @attributes.has_key?(attr_name) and options.blank?
      super(attr_name)
    # Elsif the column exist, we try to lazy load it
    elsif !(is_loaded?(attr_name)) and attr_name != self.class.primary_key and !new_record?
      unless self.all_attributes_loaded? and attr_name =~ /\A#{self.class.default_family}:/
        if options.blank?
          # Normal behavior

          # Retrieve the version of the attribute matching the current record version
          options[:timestamp] = self.updated_at.to_bigrecord_timestamp if self.has_attribute?("#{self.class.default_family}:updated_at") and self.updated_at

          # get the content of the cell
          value = connection.get(self.class.table_name, self.id, attr_name, options)

          set_loaded(attr_name)
          write_attribute(attr_name, column.type_cast(value))
        else
          # Special request... don't keep it in the attributes hash
          options[:timestamp] ||= self.updated_at.to_bigrecord_timestamp if self.has_attribute?("#{self.class.default_family}:updated_at") and self.updated_at

          # get the content of the cell
          value = connection.get(self.class.table_name, self.id, attr_name, options)

          if options[:versions] and options[:versions] > 1
            value.collect{ |v| column.type_cast(v) }
          else
            column.type_cast(value)
          end
        end
      else
        write_attribute(attr_name, column.default)
      end
    else
      write_attribute(attr_name, column.default)
    end
  else
    nil
  end
end

- (Object) read_family_attributes(attr_name)

Read an attribute that defines a column family.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/big_record/base.rb', line 83

def read_family_attributes(attr_name)
  attr_name = attr_name.to_s
  column = column_for_attribute(attr_name)
  if column
    # First check if the attribute is already in the attributes hash
    if @attributes.has_key?(attr_name)
      if (values = @attributes[attr_name]) and values.is_a?(Hash)
        values.delete(self.class.primary_key)
        casted_values = {}
        values.each{|k,v| casted_values[k] = column.type_cast(v)}
        write_attribute(attr_name, casted_values)
      else
        write_attribute(attr_name, {})
      end

    # Elsif the column exist, we try to lazy load it
    elsif !(is_loaded?(attr_name)) and attr_name != self.class.primary_key and !new_record?
      unless self.all_attributes_loaded? and attr_name =~ /\A#{self.class.default_family}:/
        options = {}
        # Retrieve the version of the attribute matching the current record version
        options[:timestamp] = self.updated_at.to_bigrecord_timestamp if self.has_attribute?("#{self.class.default_family}:updated_at") and self.updated_at

        # get the content of the whole family
        values = connection.get_columns(self.class.table_name, self.id, [attr_name], options)
        if values
          values.delete(self.class.primary_key)
          casted_values = {}
          values.each do |k,v|
            short_name = k.split(":")[1]
            casted_values[short_name] = column.type_cast(v) if short_name
            set_loaded(k)
            write_attribute(k, casted_values[short_name]) if short_name
          end
          write_attribute(attr_name, casted_values)
        else
          set_loaded(attr_name)
          write_attribute(attr_name, {})
        end
      else
        write_attribute(attr_name, column.default)
      end
    else
      write_attribute(attr_name, column.default)
    end
  else
    nil
  end
end

- (Object) save

  • No record exists: Creates a new record with values matching those of the object attributes.
  • A record does exist: Updates the record with values matching those of the object attributes.


150
151
152
# File 'lib/big_record/base.rb', line 150

def save
  create_or_update
end

- (Object) save!

Attempts to save the record, but instead of just returning false if it couldn’t happen, it raises a RecordNotSaved exception



156
157
158
# File 'lib/big_record/base.rb', line 156

def save!
  create_or_update || raise(RecordNotSaved)
end

- (Object) set_loaded(name)



132
133
134
135
# File 'lib/big_record/base.rb', line 132

def set_loaded(name)
  @loaded_columns ||= []
  @loaded_columns << name
end

- (Object) update_attribute(name, value)

Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records. Note: This method is overwritten by the Validation module that’ll make sure that updates made with this method doesn’t get subjected to validation checks. Hence, attributes can be updated even if the full object isn’t valid.



175
176
177
178
# File 'lib/big_record/base.rb', line 175

def update_attribute(name, value)
  send(name.to_s + '=', value)
  save
end

- (Object) update_attributes(attributes)

Updates all the attributes from the passed-in Hash and saves the record. If the object is invalid, the saving will fail and false will be returned.



182
183
184
185
# File 'lib/big_record/base.rb', line 182

def update_attributes(attributes)
  self.attributes = attributes
  save
end

- (Object) update_attributes!(attributes)

Updates an object just like Base.update_attributes but calls save! instead of save so an exception is raised if the record is invalid.



188
189
190
191
# File 'lib/big_record/base.rb', line 188

def update_attributes!(attributes)
  self.attributes = attributes
  save!
end