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 +4 -4
- data/.github/workflows/rubocop.yaml +1 -1
- data/.release-please-manifest.json +1 -1
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/Gemfile +3 -1
- data/benchmarks/application.rb +1 -1
- data/examples/snippets/read-only-transactions/application.rb +1 -1
- data/lib/active_record/connection_adapters/spanner/schema_creation.rb +0 -2
- data/lib/active_record/connection_adapters/spanner/schema_statements.rb +9 -0
- data/lib/activerecord_spanner_adapter/base.rb +8 -1
- data/lib/activerecord_spanner_adapter/foreign_key.rb +6 -2
- data/lib/activerecord_spanner_adapter/index/column.rb +3 -1
- data/lib/activerecord_spanner_adapter/index.rb +4 -2
- data/lib/activerecord_spanner_adapter/information_schema.rb +94 -51
- data/lib/activerecord_spanner_adapter/table/column.rb +3 -1
- data/lib/activerecord_spanner_adapter/version.rb +1 -1
- data/lib/spanner_client_ext.rb +6 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 931e6b17bf3e6d6b068c57ca879bc0dbb06933790101aa05415514c6448fd004
|
4
|
+
data.tar.gz: c4981e814899be433830e0380f69060dfa589ec39dfa7e831aad616e224030ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a989bdd8195d98206802a05294b09a53fe76c0684fba781d22dc15aaa5a38106ee3f193555cbe83e5f65254e3b39d95ed1cfb6445ded245ad80683d9752fdfd2
|
7
|
+
data.tar.gz: 0dbe1209ccad8da313fafb110bbb4fb2c1ef9ff9209230e88673f031ad02c0c372a13422fd2a5756fb0bc97a2318c003433350e071f64bcef37ba5a7754e868e
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
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
|
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
|
|
data/benchmarks/application.rb
CHANGED
@@ -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
|
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
|
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
|
-
|
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:
|
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:
|
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.
|
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
|
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
|
251
|
+
def foreign_keys from_table_name, from_schema_name: ""
|
240
252
|
sql = <<~SQL
|
241
|
-
SELECT
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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:
|
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
|
-
|
261
|
-
row["
|
262
|
-
row["
|
263
|
-
row["
|
264
|
-
row["
|
265
|
-
on_delete: row["
|
266
|
-
on_update: row["
|
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
|
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
|
data/lib/spanner_client_ext.rb
CHANGED
@@ -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
|
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.
|
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:
|
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.
|
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
|