Class: ActiveRecord::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/activerecord_spanner_adapter/base.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

._buffer_record(values, method) ⇒ Object



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
# File 'lib/activerecord_spanner_adapter/base.rb', line 100

def self._buffer_record values, method
  primary_key = self.primary_key
  primary_key_value = nil

  if primary_key && values.is_a?(Hash)
    primary_key_value = values[primary_key]
    primary_key_value ||= values[:"#{primary_key}"]

    if !primary_key_value && prefetch_primary_key?
      primary_key_value = next_sequence_value
      values[primary_key] = primary_key_value
    end
  end

   = .new self, arel_table
  columns, grpc_values = _create_grpc_values_for_insert , values

  write = Google::Cloud::Spanner::V1::Mutation::Write.new(
    table: arel_table.name,
    columns: columns,
    values: [grpc_values.list_value]
  )
  mutation = Google::Cloud::Spanner::V1::Mutation.new(
    "#{method}": write
  )

  connection.current_spanner_transaction.buffer mutation

  primary_key_value
end

._insert_record(values) ⇒ Object



90
91
92
93
94
# File 'lib/activerecord_spanner_adapter/base.rb', line 90

def self._insert_record values
  return super unless buffered_mutations?

  _buffer_record values, :insert
end

._upsert_record(values) ⇒ Object



96
97
98
# File 'lib/activerecord_spanner_adapter/base.rb', line 96

def self._upsert_record values
  _buffer_record values, :insert_or_update
end

.active_transaction?Boolean

Returns:

  • (Boolean)


142
143
144
145
# File 'lib/activerecord_spanner_adapter/base.rb', line 142

def self.active_transaction?
  current_transaction = connection.current_transaction
  !(current_transaction.nil? || current_transaction.is_a?(ConnectionAdapters::NullTransaction))
end

.buffered_mutations?Boolean

Returns:

  • (Boolean)


40
41
42
# File 'lib/activerecord_spanner_adapter/base.rb', line 40

def self.buffered_mutations?
  spanner_adapter? && connection&.current_spanner_transaction&.isolation == :buffered_mutations
end

.create(attributes = nil, &block) ⇒ Object



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

def self.create attributes = nil, &block
  return super unless spanner_adapter?
  return super if active_transaction?

  transaction isolation: :buffered_mutations do
    return super
  end
end

.create!(attributes = nil, &block) ⇒ Object

Creates an object (or multiple objects) and saves it to the database. This method will use mutations instead of DML if there is no active transaction, or if the active transaction has been created with the option isolation: :buffered_mutations.



18
19
20
21
22
23
24
25
# File 'lib/activerecord_spanner_adapter/base.rb', line 18

def self.create! attributes = nil, &block
  return super unless spanner_adapter?
  return super if active_transaction?

  transaction isolation: :buffered_mutations do
    return super
  end
end

.delete_allObject

Deletes all records of this class. This method will use mutations instead of DML if there is no active transaction, or if the active transaction has been created with the option isolation: :buffered_mutations.



133
134
135
136
137
138
139
140
# File 'lib/activerecord_spanner_adapter/base.rb', line 133

def self.delete_all
  return super unless spanner_adapter?
  return super if active_transaction?

  transaction isolation: :buffered_mutations do
    return super
  end
end

.insert_all(_attributes, _returning: nil, _unique_by: nil) ⇒ Object

Raises:

  • (NotImplementedError)


44
45
46
# File 'lib/activerecord_spanner_adapter/base.rb', line 44

def self.insert_all _attributes, _returning: nil, _unique_by: nil
  raise NotImplementedError, "Cloud Spanner does not support skip_duplicates."
end

.insert_all!(attributes, returning: nil) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/activerecord_spanner_adapter/base.rb', line 48

def self.insert_all! attributes, returning: nil
  return super unless spanner_adapter?
  return super if active_transaction? && !buffered_mutations?

  # This might seem inefficient, but is actually not, as it is only buffering a mutation locally.
  # The mutations will be sent as one batch when the transaction is committed.
  if active_transaction?
    attributes.each do |record|
      _insert_record record
    end
  else
    transaction isolation: :buffered_mutations do
      attributes.each do |record|
        _insert_record record
      end
    end
  end
end

.spanner_adapter?Boolean

Returns:

  • (Boolean)


36
37
38
# File 'lib/activerecord_spanner_adapter/base.rb', line 36

def self.spanner_adapter?
  connection.adapter_name == "spanner"
end

.unwrap_attribute(attr_or_value) ⇒ Object



147
148
149
150
151
152
153
# File 'lib/activerecord_spanner_adapter/base.rb', line 147

def self.unwrap_attribute attr_or_value
  if attr_or_value.is_a? ActiveModel::Attribute
    attr_or_value.value
  else
    attr_or_value
  end
end

.upsert_all(attributes, returning: nil, unique_by: nil) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/activerecord_spanner_adapter/base.rb', line 67

def self.upsert_all attributes, returning: nil, unique_by: nil
  return super unless spanner_adapter?
  if active_transaction? && !buffered_mutations?
    raise NotImplementedError, "Cloud Spanner does not support upsert using DML. " \
                               "Use upsert outside a transaction block or in a transaction " \
                               "block with isolation: :buffered_mutations"
  end

  # This might seem inefficient, but is actually not, as it is only buffering a mutation locally.
  # The mutations will be sent as one batch when the transaction is committed.
  if active_transaction?
    attributes.each do |record|
      _upsert_record record
    end
  else
    transaction isolation: :buffered_mutations do
      attributes.each do |record|
        _upsert_record record
      end
    end
  end
end

Instance Method Details

#destroyObject

Deletes the object in the database. This method will use mutations instead of DML if there is no active transaction, or if the active transaction has been created with the option isolation: :buffered_mutations.



170
171
172
173
174
175
176
177
# File 'lib/activerecord_spanner_adapter/base.rb', line 170

def destroy
  return super unless self.class.spanner_adapter?
  return super if self.class.active_transaction?

  transaction isolation: :buffered_mutations do
    return super
  end
end

#update(attributes) ⇒ Object

Updates the given attributes of the object in the database. This method will use mutations instead of DML if there is no active transaction, or if the active transaction has been created with the option isolation: :buffered_mutations.



158
159
160
161
162
163
164
165
# File 'lib/activerecord_spanner_adapter/base.rb', line 158

def update attributes
  return super unless self.class.spanner_adapter?
  return super if self.class.active_transaction?

  transaction isolation: :buffered_mutations do
    return super
  end
end