Closed ta1kt0me closed 3 months ago
@ta1kt0me What is the definition of your singer
model? The reason for asking is that the ActiveRecord provider by default uses a client-side generated identifier (which is a random long). My hunch is that this is what is happening in your sample application. One quick way to verify this is to run your test script twice on the emulator. If you see different identifiers for each run, then they are randomly generated.
Using bit-reversed sequences requires you to set a sequence name on the model definition. We had to add this requirement to avoid introducing a breaking change for existing applications that already used randomly generated identifiers. See this example for how to configure that: https://github.com/googleapis/ruby-spanner-activerecord/tree/main/examples/snippets/bit-reversed-sequence#example-models
@olavloite Thank you for your response.
I confirmed that running it twice generates random values. The schema for singers in the above sample code is as follows.
CREATE TABLE singers (
singer_id INT64 NOT NULL DEFAULT (GET_NEXT_SEQUENCE_VALUE(Sequence singer_id_seq)),
first_name STRING(MAX),
last_name STRING(MAX),
label_id INT64 NOT NULL DEFAULT (GET_NEXT_SEQUENCE_VALUE(Sequence label_id_seq)),
singer_info BYTES(MAX),
) PRIMARY KEY(singer_id);
Following your advice, I set the sequence_name and ran the script, and the following error occurred. I am testing it on a Database created on Cloud Spanner, not on an emulator.
model code:
class Singer < ActiveRecord::Base
self.sequence_name = :singer_id_seq
end
error message:
Mutations cannot be used to create records that use a sequence to generate the primary key. Singer uses singer_id_seq. (ActiveRecord::StatementInvalid)
The same error occurred even with a schema that removes the default value for singer_id from the definition of the singers schema.
CREATE TABLE singers (
singer_id INT64 NOT NULL,
first_name STRING(MAX),
last_name STRING(MAX),
label_id INT64 NOT NULL DEFAULT (GET_NEXT_SEQUENCE_VALUE(Sequence label_id_seq)),
singer_info BYTES(MAX),
) PRIMARY KEY(singer_id);
In this situation, is it not possible to make a call like Singer.create
?
@ta1kt0me Ah, yes, there is one more requirement: You must use at least version 7.1.x of ActiveRecord. The reason for this is that ActiveRecord completely refactored how primary keys work between version 7.0 and 7.1, and we only implemented support for bit-reversed sequences for the newest version. The major change that ActiveRecord introduced between 7.0 and 7.1 is support for composite primary keys.
Implementing it for older versions would mean that we would have to also support it using the third-party composite-primary-key
gem that was previously required in order to use composite primary keys with ActiveRecord.
We'll update the sample for bit-reversed sequences to make these requirements clearer. If you have a look at that sample application, then you'll see that is uses Singer.create
in combination with a bit-reversed sequence.
@olavloite Following the updated sample, I confirmed with a simple app using Rails 7.1.3.2 and ruby-spanner-activerecord 1.6.2 that a bit-reversed sequence is generated for PK according to the value of start_with_counter. This was very helpful. I'll update my Rails app to 7.1. Thank you very much.
When using Bit Reversed ID for the primary key in ruby-spanner-activerecord with Cloud Spanner, I encountered an issue where the generated values significantly deviate from the values specified with start_with_counter. It seems that using Bit Reversed ID for non-PK columns does not cause any issues.
Environment details
Steps to reproduce
ActiveRecord::Persistence::ClassMethods#create
BIT_REVERSE
functionsample code:
output:
When calculating the sequence generated by
singer_id_seq
, which is used for the primary keysinger_id
, with theBIT_REVERSE
function, I expect the value to be close to thestart_with_counter
specified as 101, but the result outputs values such as 7299157174066676616 and 3724318086016960488, which are significantly different from 101.