activerecord-spanner-adapter 1.6.0 → 1.6.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ad2384bb1890bb224c89a146c42f615f89c6e2892848da5e701a091d90fa95b
4
- data.tar.gz: 0e8a9c608068ff30011bc9bca68b10ab0d22b910260a37a6d4a492365adf78b0
3
+ metadata.gz: 931e6b17bf3e6d6b068c57ca879bc0dbb06933790101aa05415514c6448fd004
4
+ data.tar.gz: c4981e814899be433830e0380f69060dfa589ec39dfa7e831aad616e224030ec
5
5
  SHA512:
6
- metadata.gz: 1894765bbc1e3dfac270d73199a4f235ae95724ca18145d6850cce27c38ef2018b59e9035cf2fa91bc30d3f650e080b8eea58c3e91a66035db3a4d07c35ca1be
7
- data.tar.gz: 4a9b93d7990fa78f901864bed816e75ff5d0f9da34a530c7107f475d8fd06dc71817fbf8b2c1e0262e4656bf7ab363917ecf7b7c82315b6d5fa84cce0d22489d
6
+ metadata.gz: a989bdd8195d98206802a05294b09a53fe76c0684fba781d22dc15aaa5a38106ee3f193555cbe83e5f65254e3b39d95ed1cfb6445ded245ad80683d9752fdfd2
7
+ data.tar.gz: 0dbe1209ccad8da313fafb110bbb4fb2c1ef9ff9209230e88673f031ad02c0c372a13422fd2a5756fb0bc97a2318c003433350e071f64bcef37ba5a7754e868e
@@ -18,7 +18,7 @@ jobs:
18
18
  with:
19
19
  ruby-version: '2.7'
20
20
  - name: cache gems
21
- uses: actions/cache@v3
21
+ uses: actions/cache@v4
22
22
  with:
23
23
  path: vendor/bundle
24
24
  key: ${{ runner.os }}-rubocop-${{ hashFiles('**/Gemfile.lock') }}
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "1.6.0"
2
+ ".": "1.6.1"
3
3
  }
data/.rubocop.yml CHANGED
@@ -41,6 +41,6 @@ Style/WordArray:
41
41
  Style/RegexpLiteral:
42
42
  Enabled: false
43
43
  Metrics/MethodLength:
44
- Max: 40
44
+ Max: 60
45
45
  Metrics/BlockLength:
46
46
  Max: 30
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ### 1.6.1 (2024-02-05)
4
+
5
+ #### Bug Fixes
6
+
7
+ * _insert_record failed for other adapters ([#298](https://github.com/googleapis/ruby-spanner-activerecord/issues/298))
8
+
3
9
  ### 1.6.0 (2023-12-20)
4
10
 
5
11
  #### Features
data/Gemfile CHANGED
@@ -8,9 +8,11 @@ gem "minitest", "~> 5.20.0"
8
8
  gem "minitest-rg", "~> 5.3.0"
9
9
  gem "pry", "~> 0.13.0"
10
10
  gem "pry-byebug", "~> 3.9.0"
11
+ # Add sqlite3 for testing for compatibility with other adapters.
12
+ gem "sqlite3"
11
13
 
12
14
  # Required for samples and testing.
13
- install_if -> { ENV.fetch("AR_VERSION", "~> 6.1.6.1").dup.to_s.sub!("~>", "").strip < "7.1.0" && !ENV["SKIP_COMPOSITE_PK"] } do
15
+ install_if -> { ENV.fetch("AR_VERSION", "~> 6.1.6.1").dup.to_s.sub("~>", "").strip < "7.1.0" && !ENV["SKIP_COMPOSITE_PK"] } do
14
16
  gem "composite_primary_keys"
15
17
  end
16
18
 
@@ -12,7 +12,7 @@ require_relative "models/singer"
12
12
  require_relative "models/album"
13
13
 
14
14
  class Application
15
- def self.run # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
15
+ def self.run # rubocop:disable Metrics/AbcSize
16
16
  ActiveRecord::Base.logger.level = Logger::WARN
17
17
  config = ActiveRecord::Base.connection_config
18
18
  spanner = Google::Cloud::Spanner.new project: config[:project], credentials: config[:credentials]
@@ -10,7 +10,7 @@ require_relative "models/singer"
10
10
  require_relative "models/album"
11
11
 
12
12
  class Application
13
- def self.run # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
13
+ def self.run # rubocop:disable Metrics/AbcSize
14
14
  # Use a read-only transaction to execute multiple reads at the same commit timestamp.
15
15
  # The Spanner ActiveRecord adapter supports the custom isolation level :read_only that
16
16
  # will start a read-only Spanner transaction with a strong timestamp bound.
@@ -11,7 +11,6 @@ module ActiveRecord
11
11
  private
12
12
 
13
13
  # rubocop:disable Naming/MethodName, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
14
- # rubocop:disable Metrics/MethodLength
15
14
 
16
15
  def visit_TableDefinition o
17
16
  create_sql = +"CREATE TABLE #{quote_table_name o.name} "
@@ -133,7 +132,6 @@ module ActiveRecord
133
132
  end
134
133
 
135
134
  # rubocop:enable Naming/MethodName, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
136
- # rubocop:enable Metrics/MethodLength
137
135
 
138
136
  def add_column_options! column, sql, options
139
137
  if options[:null] == false || options[:primary_key] == true
@@ -40,6 +40,15 @@ module ActiveRecord
40
40
  end
41
41
  alias data_source_exists? table_exists?
42
42
 
43
+ def extract_schema_qualified_name string
44
+ schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/)
45
+ unless name
46
+ name = schema
47
+ schema = nil
48
+ end
49
+ [schema, name]
50
+ end
51
+
43
52
  def create_table table_name, id: :primary_key, **options
44
53
  td = create_table_definition table_name, options
45
54
 
@@ -49,7 +49,10 @@ module ActiveRecord
49
49
  end
50
50
 
51
51
  def self._insert_record values, returning = []
52
- return super unless buffered_mutations? || (primary_key && values.is_a?(Hash))
52
+ if !(buffered_mutations? || (primary_key && values.is_a?(Hash))) || !spanner_adapter?
53
+ return super values if ActiveRecord.gem_version < VERSION_7_1
54
+ return super
55
+ end
53
56
 
54
57
  # Mutations cannot be used in combination with a sequence, as mutations do not support a THEN RETURN clause.
55
58
  if buffered_mutations? && sequence_name
@@ -59,6 +62,10 @@ module ActiveRecord
59
62
 
60
63
  return _buffer_record values, :insert, returning if buffered_mutations?
61
64
 
65
+ _insert_record_dml values, returning
66
+ end
67
+
68
+ def self._insert_record_dml values, returning
62
69
  primary_key_value = _set_primary_key_value values
63
70
  if ActiveRecord::VERSION::MAJOR >= 7
64
71
  im = Arel::InsertManager.new arel_table
@@ -6,7 +6,7 @@
6
6
 
7
7
  module ActiveRecordSpannerAdapter
8
8
  class ForeignKey
9
- attr_accessor :table_name, :name, :columns, :ref_table, :ref_columns,
9
+ attr_accessor :table_schema, :table_name, :name, :columns, :ref_schema, :ref_table, :ref_columns,
10
10
  :on_delete, :on_update
11
11
 
12
12
  def initialize \
@@ -16,10 +16,14 @@ module ActiveRecordSpannerAdapter
16
16
  ref_table,
17
17
  ref_columns,
18
18
  on_delete: nil,
19
- on_update: nil
19
+ on_update: nil,
20
+ table_schema: "",
21
+ ref_schema: ""
22
+ @table_schema = table_schema
20
23
  @table_name = table_name
21
24
  @name = name
22
25
  @columns = Array(columns)
26
+ @ref_schema = ref_schema
23
27
  @ref_table = ref_table
24
28
  @ref_columns = Array(ref_columns)
25
29
  @on_delete = on_delete unless on_delete == "NO ACTION"
@@ -7,16 +7,18 @@
7
7
  module ActiveRecordSpannerAdapter
8
8
  class Index
9
9
  class Column
10
- attr_accessor :table_name, :index_name, :name, :order, :ordinal_position
10
+ attr_accessor :table_name, :schema_name, :index_name, :name, :order, :ordinal_position
11
11
 
12
12
  def initialize \
13
13
  table_name,
14
14
  index_name,
15
15
  name,
16
+ schema_name: "",
16
17
  order: nil,
17
18
  ordinal_position: nil
18
19
  @table_name = table_name.to_s
19
20
  @index_name = index_name.to_s
21
+ @schema_name = schema_name.to_s
20
22
  @name = name.to_s
21
23
  @order = order.to_s.upcase if order
22
24
  @ordinal_position = ordinal_position
@@ -8,7 +8,7 @@ require "activerecord_spanner_adapter/index/column"
8
8
 
9
9
  module ActiveRecordSpannerAdapter
10
10
  class Index
11
- attr_accessor :table, :name, :columns, :type, :unique, :null_filtered,
11
+ attr_accessor :schema, :table, :name, :columns, :type, :unique, :null_filtered,
12
12
  :interleave_in, :storing, :state
13
13
 
14
14
  def initialize \
@@ -20,7 +20,9 @@ module ActiveRecordSpannerAdapter
20
20
  null_filtered: false,
21
21
  interleave_in: nil,
22
22
  storing: nil,
23
- state: nil
23
+ state: nil,
24
+ schema: ""
25
+ @schema = schema.to_s
24
26
  @table = table.to_s
25
27
  @name = name.to_s
26
28
  @columns = Array(columns)
@@ -24,7 +24,7 @@ module ActiveRecordSpannerAdapter
24
24
  @mutex = Mutex.new
25
25
  end
26
26
 
27
- def tables table_name: nil, schema_name: nil, view: nil
27
+ def tables table_name: nil, schema_name: "", view: nil
28
28
  sql = +"SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, PARENT_TABLE_NAME, ON_DELETE_ACTION"
29
29
  sql << " FROM INFORMATION_SCHEMA.TABLES"
30
30
  sql << " WHERE TABLE_SCHEMA=%<schema_name>s"
@@ -45,17 +45,17 @@ module ActiveRecordSpannerAdapter
45
45
  )
46
46
 
47
47
  if [:full, :columns].include? view
48
- table.columns = table_columns table.name
48
+ table.columns = table_columns table.name, schema_name: schema_name
49
49
  end
50
50
 
51
51
  if [:full, :indexes].include? view
52
- table.indexes = indexes table.name
52
+ table.indexes = indexes table.name, schema_name: table.schema_name
53
53
  end
54
54
  table
55
55
  end
56
56
  end
57
57
 
58
- def table table_name, schema_name: nil, view: nil
58
+ def table table_name, schema_name: "", view: nil
59
59
  tables(
60
60
  table_name: table_name,
61
61
  schema_name: schema_name,
@@ -63,26 +63,28 @@ module ActiveRecordSpannerAdapter
63
63
  ).first
64
64
  end
65
65
 
66
- def table_columns table_name, column_name: nil
66
+ def table_columns table_name, column_name: nil, schema_name: ""
67
67
  primary_keys = table_primary_keys(table_name).map(&:name)
68
68
  sql = +"SELECT COLUMN_NAME, SPANNER_TYPE, IS_NULLABLE, GENERATION_EXPRESSION,"
69
69
  sql << " CAST(COLUMN_DEFAULT AS STRING) AS COLUMN_DEFAULT, ORDINAL_POSITION"
70
70
  sql << " FROM INFORMATION_SCHEMA.COLUMNS"
71
71
  sql << " WHERE TABLE_NAME=%<table_name>s"
72
+ sql << " AND TABLE_SCHEMA=%<schema_name>s"
72
73
  sql << " AND COLUMN_NAME=%<column_name>s" if column_name
73
74
  sql << " ORDER BY ORDINAL_POSITION ASC"
74
75
 
75
- column_options = column_options table_name, column_name
76
+ column_options = column_options table_name, column_name, schema_name: schema_name
76
77
  execute_query(
77
78
  sql,
78
79
  table_name: table_name,
79
- column_name: column_name
80
+ column_name: column_name,
81
+ schema_name: schema_name
80
82
  ).map do |row|
81
- _create_column table_name, row, primary_keys, column_options
83
+ _create_column table_name, row, primary_keys, column_options, schema_name: schema_name
82
84
  end
83
85
  end
84
86
 
85
- def _create_column table_name, row, primary_keys, column_options
87
+ def _create_column table_name, row, primary_keys, column_options, schema_name: ""
86
88
  type, limit = parse_type_and_limit row["SPANNER_TYPE"]
87
89
  column_name = row["COLUMN_NAME"]
88
90
  options = column_options[column_name]
@@ -104,6 +106,7 @@ module ActiveRecordSpannerAdapter
104
106
  table_name,
105
107
  column_name,
106
108
  type,
109
+ schema_name: schema_name,
107
110
  limit: limit,
108
111
  allow_commit_timestamp: options["allow_commit_timestamp"],
109
112
  ordinal_position: row["ORDINAL_POSITION"],
@@ -114,8 +117,8 @@ module ActiveRecordSpannerAdapter
114
117
  primary_key: primary_key
115
118
  end
116
119
 
117
- def table_column table_name, column_name
118
- table_columns(table_name, column_name: column_name).first
120
+ def table_column table_name, column_name, schema_name: ""
121
+ table_columns(table_name, column_name: column_name, schema_name: schema_name).first
119
122
  end
120
123
 
121
124
  # Returns the primary key columns of the given table. By default it will only return the columns that are not part
@@ -123,43 +126,49 @@ module ActiveRecordSpannerAdapter
123
126
  # ActiveRecord. The parent primary key columns are filtered out by default to allow interleaved tables to be
124
127
  # considered as tables with a single-column primary key by ActiveRecord. The actual primary key of the table will
125
128
  # include both the parent primary key columns and the 'own' primary key columns of a table.
126
- def table_primary_keys table_name, include_parent_keys = IsRails71OrLater
129
+ def table_primary_keys table_name, include_parent_keys = IsRails71OrLater, schema_name: ""
127
130
  sql = +"WITH TABLE_PK_COLS AS ( "
128
- sql << "SELECT C.TABLE_NAME, C.COLUMN_NAME, C.INDEX_NAME, C.COLUMN_ORDERING, C.ORDINAL_POSITION "
131
+ sql << "SELECT C.TABLE_CATALOG, C.TABLE_SCHEMA, C.TABLE_NAME, C.COLUMN_NAME, "
132
+ sql << "C.INDEX_NAME, C.COLUMN_ORDERING, C.ORDINAL_POSITION "
129
133
  sql << "FROM INFORMATION_SCHEMA.INDEX_COLUMNS C "
130
134
  sql << "WHERE C.INDEX_TYPE = 'PRIMARY_KEY' "
131
135
  sql << "AND TABLE_CATALOG = '' "
132
136
  sql << "AND TABLE_SCHEMA = '') "
133
137
  sql << "SELECT INDEX_NAME, COLUMN_NAME, COLUMN_ORDERING, ORDINAL_POSITION "
134
138
  sql << "FROM TABLE_PK_COLS "
135
- sql << "INNER JOIN INFORMATION_SCHEMA.TABLES T USING (TABLE_NAME) "
139
+ sql << "INNER JOIN INFORMATION_SCHEMA.TABLES T USING (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME) "
136
140
  sql << "WHERE TABLE_NAME = %<table_name>s "
137
141
  sql << "AND TABLE_CATALOG = '' "
138
- sql << "AND TABLE_SCHEMA = '' "
142
+ sql << "AND TABLE_SCHEMA = %<schema_name>s "
139
143
  unless include_parent_keys
140
144
  sql << "AND (T.PARENT_TABLE_NAME IS NULL OR COLUMN_NAME NOT IN ( "
141
145
  sql << " SELECT COLUMN_NAME "
142
146
  sql << " FROM TABLE_PK_COLS "
143
- sql << " WHERE TABLE_NAME = T.PARENT_TABLE_NAME "
147
+ sql << " WHERE TABLE_CATALOG = T.TABLE_CATALOG "
148
+ sql << " AND TABLE_SCHEMA=T.TABLE_SCHEMA "
149
+ sql << " AND TABLE_NAME = T.PARENT_TABLE_NAME "
144
150
  sql << ")) "
145
151
  end
146
152
  sql << "ORDER BY ORDINAL_POSITION"
147
153
  execute_query(
148
154
  sql,
149
- table_name: table_name
155
+ table_name: table_name,
156
+ schema_name: schema_name
150
157
  ).map do |row|
151
158
  Index::Column.new \
152
159
  table_name,
153
160
  row["INDEX_NAME"],
154
161
  row["COLUMN_NAME"],
162
+ schema_name: schema_name,
155
163
  order: row["COLUMN_ORDERING"],
156
164
  ordinal_position: row["ORDINAL_POSITION"]
157
165
  end
158
166
  end
159
167
 
160
- def indexes table_name, index_name: nil, index_type: nil
168
+ def indexes table_name, schema_name: "", index_name: nil, index_type: nil
161
169
  table_indexes_columns = index_columns(
162
170
  table_name,
171
+ schema_name: schema_name,
163
172
  index_name: index_name
164
173
  )
165
174
 
@@ -167,7 +176,7 @@ module ActiveRecordSpannerAdapter
167
176
  sql << " FROM INFORMATION_SCHEMA.INDEXES"
168
177
  sql << " WHERE TABLE_NAME=%<table_name>s"
169
178
  sql << " AND TABLE_CATALOG = ''"
170
- sql << " AND TABLE_SCHEMA = ''"
179
+ sql << " AND TABLE_SCHEMA = %<schema_name>s"
171
180
  sql << " AND INDEX_NAME=%<index_name>s" if index_name
172
181
  sql << " AND INDEX_TYPE=%<index_type>s" if index_type
173
182
  sql << " AND SPANNER_IS_MANAGED=FALSE"
@@ -175,6 +184,7 @@ module ActiveRecordSpannerAdapter
175
184
  execute_query(
176
185
  sql,
177
186
  table_name: table_name,
187
+ schema_name: schema_name,
178
188
  index_name: index_name,
179
189
  index_type: index_type
180
190
  ).map do |row|
@@ -198,89 +208,120 @@ module ActiveRecordSpannerAdapter
198
208
  null_filtered: row["IS_NULL_FILTERED"],
199
209
  interleave_in: row["PARENT_TABLE_NAME"],
200
210
  storing: storing,
201
- state: row["INDEX_STATE"]
211
+ state: row["INDEX_STATE"],
212
+ schema: schema_name
202
213
  end
203
214
  end
204
215
 
205
- def index table_name, index_name
206
- indexes(table_name, index_name: index_name).first
216
+ def index table_name, index_name, schema_name: ""
217
+ indexes(table_name, index_name: index_name, schema_name: schema_name).first
207
218
  end
208
219
 
209
- def index_columns table_name, index_name: nil
220
+ def index_columns table_name, schema_name: "", index_name: nil
210
221
  sql = +"SELECT INDEX_NAME, COLUMN_NAME, COLUMN_ORDERING, ORDINAL_POSITION"
211
222
  sql << " FROM INFORMATION_SCHEMA.INDEX_COLUMNS"
212
223
  sql << " WHERE TABLE_NAME=%<table_name>s"
213
224
  sql << " AND TABLE_CATALOG = ''"
214
- sql << " AND TABLE_SCHEMA = ''"
225
+ sql << " AND TABLE_SCHEMA = %<schema_name>s"
215
226
  sql << " AND INDEX_NAME=%<index_name>s" if index_name
216
227
  sql << " ORDER BY ORDINAL_POSITION ASC"
217
228
 
218
229
  execute_query(
219
230
  sql,
220
- table_name: table_name, index_name: index_name
231
+ table_name: table_name, schema_name: schema_name, index_name: index_name
221
232
  ).map do |row|
222
233
  Index::Column.new \
223
234
  table_name,
224
235
  row["INDEX_NAME"],
225
236
  row["COLUMN_NAME"],
237
+ schema_name: schema_name,
226
238
  order: row["COLUMN_ORDERING"],
227
239
  ordinal_position: row["ORDINAL_POSITION"]
228
240
  end
229
241
  end
230
242
 
231
- def indexes_by_columns table_name, column_names
243
+ def indexes_by_columns table_name, column_names, schema_name: ""
232
244
  column_names = Array(column_names).map(&:to_s)
233
245
 
234
- indexes(table_name).select do |index|
246
+ indexes(table_name, schema_name: schema_name).select do |index|
235
247
  index.columns.any? { |c| column_names.include? c.name }
236
248
  end
237
249
  end
238
250
 
239
- def foreign_keys table_name
251
+ def foreign_keys from_table_name, from_schema_name: ""
240
252
  sql = <<~SQL
241
- SELECT cc.table_name AS to_table,
242
- cc.column_name AS primary_key,
243
- fk.column_name as column,
244
- fk.constraint_name AS name,
245
- rc.update_rule AS on_update,
246
- rc.delete_rule AS on_delete
247
- FROM information_schema.referential_constraints rc
248
- INNER JOIN information_schema.key_column_usage fk ON rc.constraint_name = fk.constraint_name
249
- INNER JOIN information_schema.constraint_column_usage cc ON rc.constraint_name = cc.constraint_name
250
- WHERE fk.table_name = %<table_name>s
251
- AND fk.constraint_schema = %<constraint_schema>s
253
+ SELECT CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, UPDATE_RULE, DELETE_RULE,
254
+ FK_CATALOG, FK_SCHEMA, FK_TABLE,
255
+ PK_CATALOG, PK_SCHEMA, PK_TABLE,
256
+ ARRAY_AGG(FK_COLUMN) AS FK_COLUMNS, ARRAY_AGG(PK_COLUMN) AS PK_COLUMNS
257
+ FROM (SELECT CONSTRAINTS.CONSTRAINT_CATALOG,
258
+ CONSTRAINTS.CONSTRAINT_SCHEMA,
259
+ CONSTRAINTS.CONSTRAINT_NAME,
260
+ CONSTRAINTS.UPDATE_RULE,
261
+ CONSTRAINTS.DELETE_RULE,
262
+ CHILD.TABLE_CATALOG AS FK_CATALOG,
263
+ CHILD.TABLE_SCHEMA AS FK_SCHEMA,
264
+ CHILD.TABLE_NAME AS FK_TABLE,
265
+ CHILD.COLUMN_NAME AS FK_COLUMN,
266
+ PARENT.TABLE_CATALOG AS PK_CATALOG,
267
+ PARENT.TABLE_SCHEMA AS PK_SCHEMA,
268
+ PARENT.TABLE_NAME AS PK_TABLE,
269
+ PARENT.COLUMN_NAME AS PK_COLUMN
270
+ FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS CONSTRAINTS
271
+ INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CHILD
272
+ ON CONSTRAINTS.CONSTRAINT_CATALOG = CHILD.CONSTRAINT_CATALOG
273
+ AND CONSTRAINTS.CONSTRAINT_SCHEMA = CHILD.CONSTRAINT_SCHEMA
274
+ AND CONSTRAINTS.CONSTRAINT_NAME = CHILD.CONSTRAINT_NAME
275
+ INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE PARENT
276
+ ON CONSTRAINTS.UNIQUE_CONSTRAINT_CATALOG = PARENT.CONSTRAINT_CATALOG
277
+ AND CONSTRAINTS.UNIQUE_CONSTRAINT_SCHEMA = PARENT.CONSTRAINT_SCHEMA
278
+ AND CONSTRAINTS.UNIQUE_CONSTRAINT_NAME = PARENT.CONSTRAINT_NAME
279
+ AND PARENT.ORDINAL_POSITION = CHILD.POSITION_IN_UNIQUE_CONSTRAINT
280
+ ORDER BY CHILD.TABLE_CATALOG, CHILD.TABLE_SCHEMA, CHILD.TABLE_NAME, CHILD.POSITION_IN_UNIQUE_CONSTRAINT
281
+ ) FOREIGN_KEYS
282
+ WHERE FK_TABLE = %<table_name>s
283
+ AND FK_SCHEMA = %<constraint_schema>s
284
+ GROUP BY CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, UPDATE_RULE, DELETE_RULE,
285
+ FK_CATALOG, FK_SCHEMA, FK_TABLE,
286
+ PK_CATALOG, PK_SCHEMA, PK_TABLE
252
287
  SQL
253
288
 
254
289
  rows = execute_query(
255
- sql, table_name: table_name, constraint_schema: ""
290
+ sql, table_name: from_table_name, constraint_schema: from_schema_name
256
291
  )
257
292
 
258
293
  rows.map do |row|
259
294
  ForeignKey.new(
260
- table_name,
261
- row["name"],
262
- row["column"],
263
- row["to_table"],
264
- row["primary_key"],
265
- on_delete: row["on_delete"],
266
- on_update: row["on_update"]
295
+ from_table_name,
296
+ row["CONSTRAINT_NAME"],
297
+ row["FK_COLUMNS"],
298
+ row["PK_TABLE"],
299
+ row["PK_COLUMNS"],
300
+ on_delete: row["DELETE_RULE"],
301
+ on_update: row["UPDATE_RULE"],
302
+ table_schema: from_schema_name,
303
+ ref_schema: row["PK_SCHEMA"]
267
304
  )
268
305
  end
269
306
  end
270
307
 
271
- def check_constraints table_name
308
+ def check_constraints table_name, schema_name: ""
272
309
  sql = <<~SQL.squish
273
310
  SELECT tc.TABLE_NAME,
274
311
  tc.CONSTRAINT_NAME,
275
312
  cc.CHECK_CLAUSE
276
313
  FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
277
- INNER JOIN INFORMATION_SCHEMA.CHECK_CONSTRAINTS cc ON tc.CONSTRAINT_NAME = cc.CONSTRAINT_NAME
314
+ INNER JOIN INFORMATION_SCHEMA.CHECK_CONSTRAINTS cc
315
+ ON tc.CONSTRAINT_CATALOG = cc.CONSTRAINT_CATALOG
316
+ AND tc.CONSTRAINT_SCHEMA = cc.CONSTRAINT_SCHEMA
317
+ AND tc.CONSTRAINT_NAME = cc.CONSTRAINT_NAME
278
318
  WHERE tc.TABLE_NAME = %<table_name>s
319
+ AND tc.CONSTRAINT_SCHEMA = %<schema_name>s
279
320
  AND tc.CONSTRAINT_TYPE = 'CHECK'
280
321
  AND NOT (tc.CONSTRAINT_NAME LIKE 'CK_IS_NOT_NULL_%%' AND cc.CHECK_CLAUSE LIKE '%%IS NOT NULL')
281
322
  SQL
282
323
 
283
- rows = execute_query sql, table_name: table_name
324
+ rows = execute_query sql, table_name: table_name, schema_name: schema_name
284
325
 
285
326
  rows.map do |row|
286
327
  ActiveRecord::ConnectionAdapters::CheckConstraintDefinition.new(
@@ -363,16 +404,18 @@ module ActiveRecordSpannerAdapter
363
404
  [value[start...(start + length)].to_i(base)].pack "U"
364
405
  end
365
406
 
366
- def column_options table_name, column_name
407
+ def column_options table_name, column_name, schema_name: ""
367
408
  sql = +"SELECT COLUMN_NAME, OPTION_NAME, OPTION_TYPE, OPTION_VALUE"
368
409
  sql << " FROM INFORMATION_SCHEMA.COLUMN_OPTIONS"
369
410
  sql << " WHERE TABLE_NAME=%<table_name>s"
411
+ sql << " AND TABLE_SCHEMA=%<schema_name>s"
370
412
  sql << " AND COLUMN_NAME=%<column_name>s" if column_name
371
413
 
372
414
  column_options = Hash.new { |h, k| h[k] = {} }
373
415
  execute_query(
374
416
  sql,
375
417
  table_name: table_name,
418
+ schema_name: schema_name,
376
419
  column_name: column_name
377
420
  ).each_with_object(column_options) do |row, options|
378
421
  next unless row["OPTION_TYPE"] == "BOOL"
@@ -7,7 +7,7 @@
7
7
  module ActiveRecordSpannerAdapter
8
8
  class Table
9
9
  class Column
10
- attr_accessor :table_name, :name, :type, :limit, :ordinal_position,
10
+ attr_accessor :schema_name, :table_name, :name, :type, :limit, :ordinal_position,
11
11
  :allow_commit_timestamp, :default, :default_function, :generated,
12
12
  :primary_key, :nullable
13
13
 
@@ -15,6 +15,7 @@ module ActiveRecordSpannerAdapter
15
15
  table_name,
16
16
  name,
17
17
  type,
18
+ schema_name: "",
18
19
  limit: nil,
19
20
  ordinal_position: nil,
20
21
  nullable: true,
@@ -23,6 +24,7 @@ module ActiveRecordSpannerAdapter
23
24
  default_function: nil,
24
25
  generated: nil,
25
26
  primary_key: false
27
+ @schema_name = schema_name.to_s
26
28
  @table_name = table_name.to_s
27
29
  @name = name.to_s
28
30
  @type = type
@@ -5,5 +5,5 @@
5
5
  # https://opensource.org/licenses/MIT.
6
6
 
7
7
  module ActiveRecordSpannerAdapter
8
- VERSION = "1.6.0".freeze
8
+ VERSION = "1.6.1".freeze
9
9
  end
@@ -68,7 +68,12 @@ module Google
68
68
  snp_grpc = service.create_snapshot \
69
69
  path, timestamp: (timestamp || read_timestamp),
70
70
  staleness: (staleness || exact_staleness)
71
- Snapshot.from_grpc snp_grpc, self
71
+ num_args = Snapshot.method(:from_grpc).arity
72
+ if num_args == 3
73
+ Snapshot.from_grpc snp_grpc, self, nil
74
+ else
75
+ Snapshot.from_grpc snp_grpc, self
76
+ end
72
77
  end
73
78
 
74
79
  def create_pdml
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-spanner-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Google LLC
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-20 00:00:00.000000000 Z
11
+ date: 2024-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-cloud-spanner
@@ -577,7 +577,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
577
577
  - !ruby/object:Gem::Version
578
578
  version: '0'
579
579
  requirements: []
580
- rubygems_version: 3.4.19
580
+ rubygems_version: 3.5.3
581
581
  signing_key:
582
582
  specification_version: 4
583
583
  summary: Rails ActiveRecord connector for Google Spanner Database