diff --git a/google-cloud-spanner/Gemfile b/google-cloud-spanner/Gemfile index cb0c22cc..0a88531d 100644 --- a/google-cloud-spanner/Gemfile +++ b/google-cloud-spanner/Gemfile @@ -8,7 +8,7 @@ gem "google-cloud-core", "~> 1.8.0" gem "google-cloud-errors", "~> 1.5.0" gem "google-cloud-spanner-admin-database-v1", "~> 1.3" gem "google-cloud-spanner-admin-instance-v1", "~> 1.5" -gem "google-cloud-spanner-v1", "~> 1.5" +gem "google-cloud-spanner-v1", "~> 1.8" gem "google-style", "~> 1.31.0" gem "grpc", "~> 1.67" gem "grpc-tools", "~> 1.74", ">= 1.74.1" diff --git a/google-cloud-spanner/lib/google/cloud/spanner/client.rb b/google-cloud-spanner/lib/google/cloud/spanner/client.rb index 6929ed8f..60283426 100644 --- a/google-cloud-spanner/lib/google/cloud/spanner/client.rb +++ b/google-cloud-spanner/lib/google/cloud/spanner/client.rb @@ -1053,6 +1053,8 @@ def read table, columns, keys: nil, index: nil, limit: nil, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1143,7 +1145,7 @@ def read table, columns, keys: nil, index: nil, limit: nil, # request_options: request_options # def upsert table, rows, - exclude_txn_from_change_streams: false, + exclude_txn_from_change_streams: false, isolation_level: nil, commit_options: nil, request_options: nil, call_options: nil request_options = Convert.to_request_options \ request_options, tag_type: :transaction_tag @@ -1151,6 +1153,7 @@ def upsert table, rows, @pool.with_session do |session| session.upsert table, rows, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -1200,6 +1203,8 @@ def upsert table, rows, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1290,7 +1295,7 @@ def upsert table, rows, # request_options: request_options # def insert table, rows, - exclude_txn_from_change_streams: false, + exclude_txn_from_change_streams: false, isolation_level: nil, commit_options: nil, request_options: nil, call_options: nil request_options = Convert.to_request_options \ request_options, tag_type: :transaction_tag @@ -1298,6 +1303,7 @@ def insert table, rows, @pool.with_session do |session| session.insert table, rows, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -1346,6 +1352,8 @@ def insert table, rows, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1435,7 +1443,7 @@ def insert table, rows, # request_options: request_options # def update table, rows, - exclude_txn_from_change_streams: false, + exclude_txn_from_change_streams: false, isolation_level: nil, commit_options: nil, request_options: nil, call_options: nil request_options = Convert.to_request_options \ request_options, tag_type: :transaction_tag @@ -1443,6 +1451,7 @@ def update table, rows, @pool.with_session do |session| session.update table, rows, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -1493,6 +1502,8 @@ def update table, rows, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1582,11 +1593,12 @@ def update table, rows, # request_options: request_options # def replace table, rows, - exclude_txn_from_change_streams: false, + exclude_txn_from_change_streams: false, isolation_level: nil, commit_options: nil, request_options: nil, call_options: nil @pool.with_session do |session| session.replace table, rows, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -1616,6 +1628,8 @@ def replace table, rows, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1699,13 +1713,15 @@ def replace table, rows, # def delete table, keys = [], exclude_txn_from_change_streams: false, - commit_options: nil, request_options: nil, call_options: nil + isolation_level: nil, commit_options: nil, request_options: nil, + call_options: nil request_options = Convert.to_request_options \ request_options, tag_type: :transaction_tag @pool.with_session do |session| session.delete table, keys, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -1730,6 +1746,8 @@ def delete table, keys = [], # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1826,6 +1844,7 @@ def delete table, keys = [], # end # def commit exclude_txn_from_change_streams: false, + isolation_level: nil, commit_options: nil, request_options: nil, call_options: nil, &block raise ArgumentError, "Must provide a block" unless block_given? @@ -1836,6 +1855,7 @@ def commit exclude_txn_from_change_streams: false, @pool.with_session do |session| session.commit( exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options, &block ) diff --git a/google-cloud-spanner/lib/google/cloud/spanner/service.rb b/google-cloud-spanner/lib/google/cloud/spanner/service.rb index cf1594d5..fcede55a 100644 --- a/google-cloud-spanner/lib/google/cloud/spanner/service.rb +++ b/google-cloud-spanner/lib/google/cloud/spanner/service.rb @@ -534,13 +534,15 @@ def partition_query session_name, sql, transaction, params: nil, # @return [::Google::Cloud::Spanner::V1::CommitResponse] def commit session_name, mutations = [], transaction_id: nil, exclude_txn_from_change_streams: false, - commit_options: nil, request_options: nil, call_options: nil + isolation_level: nil, commit_options: nil, request_options: nil, + call_options: nil route_to_leader = LARHeaders.commit tx_opts = nil if transaction_id.nil? tx_opts = V1::TransactionOptions.new( read_write: V1::TransactionOptions::ReadWrite.new, - exclude_txn_from_change_streams: exclude_txn_from_change_streams + exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level ) end opts = default_options session_name: session_name, @@ -589,12 +591,14 @@ def rollback session_name, transaction_id, call_options: nil def begin_transaction session_name, exclude_txn_from_change_streams: false, + isolation_level: nil, request_options: nil, call_options: nil, route_to_leader: nil tx_opts = V1::TransactionOptions.new( read_write: V1::TransactionOptions::ReadWrite.new, - exclude_txn_from_change_streams: exclude_txn_from_change_streams + exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level ) opts = default_options session_name: session_name, call_options: call_options, @@ -626,7 +630,7 @@ def batch_write session_name, end def create_snapshot session_name, strong: nil, timestamp: nil, - staleness: nil, call_options: nil + isolation_level: nil, staleness: nil, call_options: nil tx_opts = V1::TransactionOptions.new( read_only: V1::TransactionOptions::ReadOnly.new( { @@ -635,7 +639,8 @@ def create_snapshot session_name, strong: nil, timestamp: nil, exact_staleness: Convert.number_to_duration(staleness), return_read_timestamp: true }.compact - ) + ), + isolation_level: isolation_level ) opts = default_options session_name: session_name, call_options: call_options @@ -645,10 +650,12 @@ def create_snapshot session_name, strong: nil, timestamp: nil, def create_pdml session_name, exclude_txn_from_change_streams: false, + isolation_level: nil, call_options: nil tx_opts = V1::TransactionOptions.new( partitioned_dml: V1::TransactionOptions::PartitionedDml.new, - exclude_txn_from_change_streams: exclude_txn_from_change_streams + exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level ) route_to_leader = LARHeaders.begin_transaction true opts = default_options session_name: session_name, diff --git a/google-cloud-spanner/lib/google/cloud/spanner/session.rb b/google-cloud-spanner/lib/google/cloud/spanner/session.rb index 573459cf..eb9fa877 100644 --- a/google-cloud-spanner/lib/google/cloud/spanner/session.rb +++ b/google-cloud-spanner/lib/google/cloud/spanner/session.rb @@ -593,6 +593,8 @@ def partition_read table, columns, transaction, keys: nil, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. Used if starting a new transaction. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -671,13 +673,15 @@ def partition_read table, columns, transaction, keys: nil, # puts commit_resp.stats.mutation_count # def commit transaction_id: nil, exclude_txn_from_change_streams: false, - commit_options: nil, request_options: nil, call_options: nil + isolation_level: nil, commit_options: nil, request_options: nil, + call_options: nil ensure_service! commit = Commit.new yield commit commit_resp = service.commit path, commit.mutations, transaction_id: transaction_id, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -818,6 +822,8 @@ def batch_write exclude_txn_from_change_streams: false, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. Used if starting a new transaction. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -890,10 +896,12 @@ def batch_write exclude_txn_from_change_streams: false, # def upsert table, *rows, transaction_id: nil, exclude_txn_from_change_streams: false, - commit_options: nil, request_options: nil, call_options: nil + isolation_level: nil, commit_options: nil, request_options: nil, + call_options: nil opts = { transaction_id: transaction_id, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -938,6 +946,8 @@ def upsert table, *rows, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. Used if starting a new transaction. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1010,10 +1020,12 @@ def upsert table, *rows, # def insert table, *rows, transaction_id: nil, exclude_txn_from_change_streams: false, - commit_options: nil, request_options: nil, call_options: nil + isolation_level: nil, commit_options: nil, request_options: nil, + call_options: nil opts = { transaction_id: transaction_id, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -1057,6 +1069,8 @@ def insert table, *rows, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. Used if starting a new transaction. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1129,10 +1143,12 @@ def insert table, *rows, # def update table, *rows, transaction_id: nil, exclude_txn_from_change_streams: false, - commit_options: nil, request_options: nil, call_options: nil + isolation_level: nil, commit_options: nil, request_options: nil, + call_options: nil opts = { transaction_id: transaction_id, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -1178,6 +1194,8 @@ def update table, *rows, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. Used if starting a new transaction. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1251,10 +1269,12 @@ def update table, *rows, # def replace table, *rows, transaction_id: nil, exclude_txn_from_change_streams: false, - commit_options: nil, request_options: nil, call_options: nil + isolation_level: nil, commit_options: nil, request_options: nil, + call_options: nil opts = { transaction_id: transaction_id, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options @@ -1279,6 +1299,8 @@ def replace table, *rows, # @param [Boolean] exclude_txn_from_change_streams If set to true, # mutations will not be recorded in change streams with DDL option # `allow_txn_exclusion=true`. Used if starting a new transaction. + # @param [Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel] isolation_level The + # isolation level for the transaction. # @param [Hash] commit_options A hash of commit options. # e.g., return_commit_stats. Commit options are optional. # The following options can be provided: @@ -1348,10 +1370,12 @@ def replace table, *rows, # def delete table, keys = [], transaction_id: nil, exclude_txn_from_change_streams: false, - commit_options: nil, request_options: nil, call_options: nil + isolation_level: nil, commit_options: nil, request_options: nil, + call_options: nil opts = { transaction_id: transaction_id, exclude_txn_from_change_streams: exclude_txn_from_change_streams, + isolation_level: isolation_level, commit_options: commit_options, request_options: request_options, call_options: call_options diff --git a/google-cloud-spanner/test/google/cloud/spanner/client/commit_test.rb b/google-cloud-spanner/test/google/cloud/spanner/client/commit_test.rb index d6415e1c..1f560484 100644 --- a/google-cloud-spanner/test/google/cloud/spanner/client/commit_test.rb +++ b/google-cloud-spanner/test/google/cloud/spanner/client/commit_test.rb @@ -37,6 +37,11 @@ Google::Cloud::Spanner::V1::TransactionOptions.new read_write: Google::Cloud::Spanner::V1::TransactionOptions::ReadWrite.new, exclude_txn_from_change_streams: true } + let(:tx_opts_isolation_level) { + Google::Cloud::Spanner::V1::TransactionOptions.new read_write: Google::Cloud::Spanner::V1::TransactionOptions::ReadWrite.new, + isolation_level: Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel::SERIALIZABLE + + } let(:default_options) { ::Gapic::CallOptions.new metadata: { "google-cloud-resource-prefix" => database_path(instance_id, database_id) } } let(:client) { spanner.client instance_id, database_id, pool: { min: 0 } } let(:mutations) { @@ -453,6 +458,28 @@ mock.verify end + it "delete all rows directly while setting isolation level" do + mutations = [ + Google::Cloud::Spanner::V1::Mutation.new( + delete: Google::Cloud::Spanner::V1::Mutation::Delete.new( + table: "users", key_set: Google::Cloud::Spanner::V1::KeySet.new(all: true) + ) + ) + ] + + mock = Minitest::Mock.new + mock.expect :create_session, session_grpc, [{database: database_path(instance_id, database_id), session: nil}, default_options] + mock.expect :commit, commit_resp, [{ session: session_grpc.name, mutations: mutations, transaction_id: nil, single_use_transaction: tx_opts_isolation_level, request_options: nil }, default_options] + spanner.service.mocked_service = mock + + timestamp = client.delete "users", [], isolation_level: Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel::SERIALIZABLE + _(timestamp).must_equal commit_time + + shutdown_client! client + + mock.verify + end + describe "commit options" do let(:commit_options) { { return_commit_stats: true } } @@ -724,4 +751,4 @@ def mock_commit_request mutations, request_options: nil mock.verify shutdown_client! client end -end \ No newline at end of file +end diff --git a/google-cloud-spanner/test/google/cloud/spanner/service_test.rb b/google-cloud-spanner/test/google/cloud/spanner/service_test.rb index b9d5f1dd..829a8d25 100644 --- a/google-cloud-spanner/test/google/cloud/spanner/service_test.rb +++ b/google-cloud-spanner/test/google/cloud/spanner/service_test.rb @@ -125,6 +125,27 @@ mocked_service.verify assert_equal expected_result, result end + + it "sets the isolation_level field" do + mocked_service = Minitest::Mock.new + expected_request = { + session: session_id, + transaction_id: nil, + single_use_transaction: Google::Cloud::Spanner::V1::TransactionOptions.new( + read_write: Google::Cloud::Spanner::V1::TransactionOptions::ReadWrite.new, + isolation_level: Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel::SERIALIZABLE + ), + mutations: [], + request_options: nil + } + expected_result = Object.new + mocked_service.expect :commit, expected_result, [expected_request, expected_call_opts] + basic_service.mocked_service = mocked_service + result = basic_service.commit session_id, [], isolation_level: Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel::SERIALIZABLE + mocked_service.verify + assert_equal expected_result, result + end + end describe "#create_pdml" do diff --git a/google-cloud-spanner/test/google/cloud/spanner/session/commit_test.rb b/google-cloud-spanner/test/google/cloud/spanner/session/commit_test.rb index 074fcd4d..f6425478 100644 --- a/google-cloud-spanner/test/google/cloud/spanner/session/commit_test.rb +++ b/google-cloud-spanner/test/google/cloud/spanner/session/commit_test.rb @@ -28,6 +28,11 @@ Google::Cloud::Spanner::V1::TransactionOptions.new read_write: Google::Cloud::Spanner::V1::TransactionOptions::ReadWrite.new, exclude_txn_from_change_streams: true } + let(:tx_opts_isolation_level) { + Google::Cloud::Spanner::V1::TransactionOptions.new read_write: Google::Cloud::Spanner::V1::TransactionOptions::ReadWrite.new, + isolation_level: Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel::REPEATABLE_READ + + } let(:default_options) { ::Gapic::CallOptions.new metadata: { "google-cloud-resource-prefix" => database_path(instance_id, database_id) } } it "commits using a block" do @@ -288,4 +293,24 @@ mock.verify end + + it "passes isolation_level" do + mutations = [ + Google::Cloud::Spanner::V1::Mutation.new( + delete: Google::Cloud::Spanner::V1::Mutation::Delete.new( + table: "users", key_set: Google::Cloud::Spanner::V1::KeySet.new(all: true) + ) + ) + ] + + mock = Minitest::Mock.new + mock.expect :commit, commit_resp, [{ session: session.path, mutations: mutations, transaction_id: nil, single_use_transaction: tx_opts_isolation_level, request_options: nil }, default_options] + session.service.mocked_service = mock + + timestamp = session.delete "users", isolation_level: Google::Cloud::Spanner::V1::TransactionOptions::IsolationLevel::REPEATABLE_READ + + _(timestamp).must_equal commit_time + + mock.verify + end end