Skip to content

Commit 493847c

Browse files
authored
feat: support IDENTITY columns for auto-generated primary keys (#352)
* feat: support IDENTITY columns for auto-generated primary keys Adds support for using IDENTITY columns for auto-generated primary keys. IDENTITY columns are backed by bit-reversed sequences in Spanner. This means that IDENTITY columns produce unique non-monotonically-increasing values that are safe to use for primary keys in Spanner. The default `id` field and `:primary_key` type in Ruby ActiveRecord are mapped to IDENTITY columns. This feature is disabled by default, as it changes the default behavior of `id` and `:primary_key` fields. These currently use a client-side generated value. Client-side generated values support mutations, while server-side generated primary key values cannot be used in combination with mutations, as Spanner cannot use a THEN RETURN clause to return these to Ruby ActiveRecord. Add the following configuration value to your configuration to enable auto-generated primary keys with IDENTITY columns: ``` default_sequence_kind: BIT_REVERSED_POSITIVE ``` This feature will be enabled by default in the next major version of this provider. * chore: cleanup
1 parent 88260e9 commit 493847c

File tree

31 files changed

+826
-248
lines changed

31 files changed

+826
-248
lines changed

README.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ __NOTE__: You do need to have [Docker](https://docs.docker.com/get-docker/) inst
7878
Some noteworthy examples in the snippets directory:
7979
- [quickstart](examples/snippets/quickstart): A simple application that shows how to create and query a simple database containing two tables.
8080
- [migrations](examples/snippets/migrations): Shows a best-practice for executing migrations on Spanner.
81+
- [auto-generated-primary-key](examples/snippets/auto-generated-primary-key): Shows how to use IDENTITY columns for primary keys.
8182
- [bit-reversed-sequences](examples/snippets/bit-reversed-sequence): Shows how to use bit-reversed sequences for primary keys.
8283
- [read-write-transactions](examples/snippets/read-write-transactions): Shows how to execute transactions on Spanner.
8384
- [read-only-transactions](examples/snippets/read-only-transactions): Shows how to execute read-only transactions on Spanner.
@@ -90,16 +91,16 @@ Some noteworthy examples in the snippets directory:
9091

9192
## Limitations
9293

93-
| Limitation | Comment | Resolution |
94-
|-----------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
95-
| Interleaved tables require composite primary keys | Spanner requires composite primary keys for interleaved tables. See [this example](examples/snippets/interleaved-tables/README.md) for an example on how to use interleaved tables with ActiveRecord | Use composite primary keys. |
96-
| Lack of sequential IDs | Spanner uses either using bit-reversed sequences or UUID4 to generated primary keys to avoid [hotspotting](https://cloud.google.com/spanner/docs/schema-design#uuid_primary_key) so you SHOULD NOT rely on IDs being sorted | Use either UUID4s or bit-reversed sequences to automatically generate primary keys. |
97-
| Table without Primary Key | Spanner support does not support tables without a primary key. | Always define a primary key for your table. |
98-
| Table names CANNOT have spaces within them whether back-ticked or not | Spanner DOES NOT support tables with spaces in them for example `Entity ID` | Ensure that your table names don't contain spaces. |
99-
| Table names CANNOT have punctuation marks and MUST contain valid UTF-8 | Spanner DOES NOT support punctuation marks e.g. periods ".", question marks "?" in table names | Ensure that your table names don't contain punctuation marks. |
100-
| Index with fields length [add_index](https://apidock.com/rails/v5.2.3/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index) | Spanner does not support index with fields length | Ensure that your database definition does not include index definitions with field lengths. |
101-
| Only GoogleSQL-dialect databases | Spanner supports both GoogleSQL- and PostgreSQL-dialect databases. This adapter only supports GoogleSQL-dialect databases. You can use the [PostgreSQL ActiveRecord provider in combination with PGAdapter](https://github.com/GoogleCloudPlatform/pgadapter/tree/postgresql-dialect/samples/ruby/activerecord) for Spanner PostgreSQL databases. | |
102-
| `rails dbconsole` is not supported. | The `rails dbconsole` is not supported for Spanner databases. | |
94+
| Limitation | Comment | Resolution |
95+
|------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|
96+
| Interleaved tables require composite primary keys | Spanner requires composite primary keys for interleaved tables. See [this example](examples/snippets/interleaved-tables/README.md) for an example on how to use interleaved tables with ActiveRecord | Use composite primary keys. |
97+
| Lack of sequential IDs | Spanner uses either bit-reversed IDENTITY columns or sequences to generated primary keys to avoid [hotspotting](https://cloud.google.com/spanner/docs/schema-design#uuid_primary_key) so you SHOULD NOT rely on IDs being sorted | Use either IDENTITY columns or bit-reversed sequences to automatically generate primary keys. |
98+
| Table without Primary Key | Spanner support does not support tables without a primary key. | Always define a primary key for your table. |
99+
| Table names CANNOT have spaces within them whether back-ticked or not | Spanner DOES NOT support tables with spaces in them for example `Entity ID` | Ensure that your table names don't contain spaces. |
100+
| Table names CANNOT have punctuation marks and MUST contain valid UTF-8 | Spanner DOES NOT support punctuation marks e.g. periods ".", question marks "?" in table names | Ensure that your table names don't contain punctuation marks. |
101+
| Index with fields length [add_index](https://apidock.com/rails/v5.2.3/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index) | Spanner does not support index with fields length | Ensure that your database definition does not include index definitions with field lengths. |
102+
| Only GoogleSQL-dialect databases | Spanner supports both GoogleSQL- and PostgreSQL-dialect databases. This adapter only supports GoogleSQL-dialect databases. You can use the [PostgreSQL ActiveRecord provider in combination with PGAdapter](https://github.com/GoogleCloudPlatform/pgadapter/tree/postgresql-dialect/samples/ruby/activerecord) for Spanner PostgreSQL databases. | |
103+
| `rails dbconsole` is not supported. | The `rails dbconsole` is not supported for Spanner databases. | |
103104

104105

105106
## Contributing

acceptance/cases/models/default_value_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_literal_default_values
3131
t.column :col_timestamp, :datetime, default: default.col_timestamp
3232
end
3333

34-
item = LiteralValue.new
34+
item = LiteralValue.new id: connection.next_sequence_value(nil)
3535
default.each_pair { |col, expected| assert_equal(expected, item[col]) }
3636
item.save!
3737
default.each_pair { |col, expected| assert_equal(expected, item[col]) }
@@ -45,7 +45,7 @@ def test_expression_default_values
4545
t.column :col_timestamp, :datetime, default: -> { "CURRENT_TIMESTAMP()" }
4646
end
4747

48-
item = ExpressionValue.create!
48+
item = ExpressionValue.create! id: connection.next_sequence_value(nil)
4949
item.reload
5050
assert_equal(BigDecimal("1.23"), item.col_numeric)
5151
assert(item.col_timestamp)

0 commit comments

Comments
 (0)