Giter VIP home page Giter VIP logo

ruby-spanner-activerecord's Introduction

Google APIs

This repository contains the original interface definitions of public Google APIs that support both REST and gRPC protocols. Reading the original interface definitions can provide a better understanding of Google APIs and help you to utilize them more efficiently. You can also use these definitions with open source tools to generate client libraries, documentation, and other artifacts.

Building

Bazel

The recommended way to build the API client libraries is through Bazel >= 4.2.2.

First, install bazel.

To build all libraries:

bazel build //...

To test all libraries:

bazel test //...

To build one library in all languages:

bazel build //google/example/library/v1/...

To build the Java package for one library:

bazel build //google/example/library/v1:google-cloud-example-library-v1-java

Bazel packages exist in all the libraries for Java, Go, Python, Ruby, Node.js, PHP and C#.

Overview

Google APIs are typically deployed as API services that are hosted under different DNS names. One API service may implement multiple APIs and multiple versions of the same API.

Google APIs use Protocol Buffers version 3 (proto3) as their Interface Definition Language (IDL) to define the API interface and the structure of the payload messages. The same interface definition is used for both REST and RPC versions of the API, which can be accessed over different wire protocols.

There are several ways of accessing Google APIs:

  1. JSON over HTTP: You can access all Google APIs directly using JSON over HTTP, using Google API client library or third-party API client libraries.

  2. Protocol Buffers over gRPC: You can access Google APIs published in this repository through GRPC, which is a high-performance binary RPC protocol over HTTP/2. It offers many useful features, including request/response multiplex and full-duplex streaming.

  3. Google Cloud Client Libraries: You can use these libraries to access Google Cloud APIs. They are based on gRPC for better performance and provide idiomatic client surface for better developer experience.

Discussions

This repo contains copies of Google API definitions and related files. For discussions or to raise issues about Google API client libraries, GRPC or Google Cloud Client Libraries please refer to the repos associated with each area.

Repository Structure

This repository uses a directory hierarchy that reflects the Google API product structure. In general, every API has its own root directory, and each major version of the API has its own subdirectory. The proto package names exactly match the directory: this makes it easy to locate the proto definitions and ensures that the generated client libraries have idiomatic namespaces in most programming languages. Alongside the API directories live the configuration files for the GAPIC toolkit.

NOTE: The major version of an API is used to indicate breaking change to the API.

Generate gRPC Source Code

To generate gRPC source code for Google APIs in this repository, you first need to install both Protocol Buffers and gRPC on your local machine, then you can run make LANGUAGE=xxx all to generate the source code. You need to integrate the generated source code into your application build system.

NOTE: The Makefile is only intended to generate source code for the entire repository. It is not for generating linkable client library for a specific API. Please see other repositories under https://github.com/googleapis for generating linkable client libraries.

Go gRPC Source Code

It is difficult to generate Go gRPC source code from this repository, since Go has different directory structure. Please use this repository instead.

ruby-spanner-activerecord's People

Contributors

aeroastro avatar bajajneha27 avatar cbarton avatar connorhd avatar dazuma avatar diptanshumittal avatar google-cloud-policy-bot[bot] avatar hengfengli avatar jiren avatar justinbeckwith avatar mghadley avatar mshibuya avatar nownabe avatar odeke-em avatar olavloite avatar release-please[bot] avatar renovate-bot avatar ruzia avatar sensuikan1973 avatar skuruppu avatar xiangshen-dk avatar yfuruyama avatar yoshi-code-bot avatar yuemori avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ruby-spanner-activerecord's Issues

Support setting an attribute to the commit timestamp of a transaction

Cloud Spanner can set a column of a record to the commit timestamp of the last transaction that updated the record. This feature can be used to create a change log for the table. It should be possible to set the attribute of a model to the commit timestamp of the transaction that last updated the record using ActiveRecord.

calculations: map between active_record.relation.calculation public methods to Cloud Spanner statements

Users will need to have functional support for Calculations and we'll need to generate appropriate SQL for

ActiveRecord statement Equivalent Cloud Spanner SQL
Table.average(column) AVG so SELECT AVG(column) from Table
Table.calculate(op, column) For either of ":count", ":sum", ":average", ":minimum", ":maximum", we'll need to translate the statement into the equivalent Cloud Spanner instruction
Table.ids SELECT id from Table
Model.maximum(column_name) Cloud Spanner has MAX so SELECT MAX(column_name) from Model
Model.minimum(column_name) Cloud Spanner has MIN
Model.pluck(columns) SELECT <columns...> from Model
Model.sum(column) SUM so SELECT sum(column) from Model

ConnectionAdapter: implement methods

I've started enumerating the methods given here https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/AbstractAdapter.html and let's use the research and table below and in https://docs.google.com/document/d/1b2l6bxJktrJUFdjQSf4z2K0dtGtOGNLU1v2lHTenV70/edit#heading=h.bo5jfmjjyija

Method Comments
active? Send a ping to the server e.g. “SELECT 1=1” or perhaps through the connection pool
adapter_name “spanner”
clear_cache!  
close noop
database_exists? Return true iff Database.creating or Database.ready
disable_extension  
disable_referential_integrity  
discard!,  
disconnect! noop
enable_extension  
extensions  
index_algorithms  
lease  
log No
prefetch_primary_key? Yes, (technically since we’ll be generating UUIDs for each generated id)
prepared_statements Implementation detail
preventing_writes?raw_connection Unresovled
reconnect! Possible
replica? Unresolved
requires_reloading? No
reset! Yes
schema_cache Unresolved
schema_cache= Unresolved
supports_advisory_locks? No
supports_bulk_alter? No
supports_comments? Yes
supports_comments_in_create? No
supports_common_table_expressions? Yes
supports_datetime_with_precision? Yes as TIMESTAMP
supports_ddl_transactions? Yes
supports_explain? No
supports_expression_index? Yes
supports_extensions? No
supports_foreign_keys? No
supports_foreign_keys_in_create? No
supports_foreign_tables? No
supports_index_sort_order? Unresolved
supports_indexes_in_create? No
supports_insert_conflict_target? Implementation detail
supports_insert_on_duplicate_skip? Implementation detail
supports_insert_on_duplicate_update? Implementation detail
supports_insert_returning? Unresolved
supports_json? No, there is not a mention in data types
supports_lazy_transactions? Unresolved, not sure
supports_materialized_views? No, Cloud Spanner does not support materialized_views
supports_multi_insert? Yes, see Transaction.#insert
supports_optimizer_hints? Unresolved
supports_partial_index? Not apparent
supports_savepoints? Unresovled
supports_transaction_isolation? Unresolved
supports_validate_constraints? No, Cloud Spanner does not support validate constraints
supports_views? No, Cloud Spanner does not support views aka stored statements
supports_virtual_columns? No, Cloud Spanner does not support virtual columns
type_cast_config_to_boolean Already implemented by base class
type_cast_config_to_integer Already implemented by base class
unprepared_statement  
verify! Same action as “active”: send a “SELECT 1=1” or use the underlying pool

namespace: use activerecord-spanner

Daniel Azuma finally got the response from Yugui and they added Google Cloud Developers as owners of activerecord-spanner. We now need to reflect that change here.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

bundler
Gemfile
  • minitest "~> 5.20.0"
  • minitest-rg "~> 5.3.0"
  • pry "~> 0.13.0"
  • pry-byebug "~> 3.9.0"
github-actions
.github/workflows/acceptance-tests-on-emulator.yaml
  • actions/checkout v4
  • ruby/setup-ruby v1
.github/workflows/acceptance-tests-on-production.yaml
  • actions/checkout v4
  • ruby/setup-ruby v1
  • google-github-actions/auth v2
  • google-github-actions/setup-gcloud v2
.github/workflows/ci.yaml
  • actions/checkout v4
  • ruby/setup-ruby v1
.github/workflows/nightly-acceptance-tests-on-emulator.yaml
  • actions/checkout v4
  • ruby/setup-ruby v1
.github/workflows/nightly-acceptance-tests-on-production.yaml
  • actions/checkout v4
  • ruby/setup-ruby v1
  • google-github-actions/auth v2
  • google-github-actions/setup-gcloud v2
.github/workflows/nightly-unit-tests.yaml
  • actions/checkout v4
  • ruby/setup-ruby v1
.github/workflows/rubocop.yaml
  • actions/checkout v4
  • ruby/setup-ruby v1
  • actions/cache v4

  • Check this box to trigger a request for Renovate to run again on this repository

6 - Use Mutations instead of DML when possible

Saves/updates outside of a transaction block should use Mutations instead of DML, as the changes cannot be read back in the same transaction anyways. Mutations are a lot faster than DML for (small) updates.

It takes hours to run acceptance test on the real Cloud Spanner

Summary

I am trying to introduce the Spanner Emulator for acceptance test. While doing that, I noticed that the acceptance test on the Cloud Spanner is significantly slower than that on the Spanner Emulator.

I would like to know whether or not this is the expected result, in other words, whether or not the problem is due to my GCP environment or not.

Since I know few people using this gem, I thought this is the best place to create an issue.

Hopefully, I would like to know the possible options to improve the test speed. They can be converted into Issues or Pull Requests.

Details

  • Cloud Spanner from GCE or my MacBook Pro
    • bundle exec rake acceptance
    • it takes more than several hours
  • Spanner Emulator on docker-compose on MacBook Pro
    • below 1 minute

Following are the partial output from the test. You can see creating table takes much longer time when running on Cloud Spanner followed by very slow examples. Although the test is executed on shared resource of Cloud Spanner instance, the approximate maginitude did not change against the CPU usage.

Spanner Emulator

Loading test schema...
-- create_table(:firms)
   -> 0.0379s
-- create_table(:customers)
   -> 0.0015s
-- create_table(:accounts)
   -> 0.0015s
-- create_table(:transactions)
   -> 0.0014s
-- create_table(:departments)
   -> 0.0016s
-- create_table(:member_types)
   -> 0.0014s
-- create_table(:members)
   -> 0.0014s
-- create_table(:memberships)
   -> 0.0014s
-- create_table(:clubs)
   -> 0.0014s
-- create_table(:authors)
   -> 0.0015s
-- create_table(:posts)
   -> 0.0018s
-- create_table(:comments)
   -> 0.0018s
-- create_table(:addresses)
   -> 0.0023s
-- create_table(:organizations)
   -> 0.0017s
Run options: --seed 36288

# Running:

...................E..F...S.....S...EEEEEEEEEEEEEEEEE......................E.EEEEEE.......................................................................E...............................................EE.......................EEE....E.EE.E.EEE..E........E..E.E.E...........................................EE...........E....

Finished in 47.569106s, 6.8111 runs/s, 9.0605 assertions/s.

##### there are many omitted error results here ######

324 runs, 431 assertions, 1 failures, 46 errors, 2 skips

Cloud Spanner

'ar-test-74603537' test db created.
Loading test schema...
-- create_table(:firms)
   -> 24.1521s
-- create_table(:customers)
   -> 23.5265s
-- create_table(:accounts)
   -> 23.2956s
-- create_table(:transactions)
   -> 23.3205s
-- create_table(:departments)
   -> 23.3046s
-- create_table(:member_types)
   -> 23.3518s
-- create_table(:members)
   -> 23.2980s
-- create_table(:memberships)
   -> 23.3585s
-- create_table(:clubs)
   -> 23.3070s
-- create_table(:authors)
   -> 23.3006s
-- create_table(:posts)
   -> 23.3243s
-- create_table(:comments)
   -> 23.3511s
-- create_table(:addresses)
   -> 23.3598s
-- create_table(:organizations)
   -> 23.3078s
Run options: --seed 57206

# Running:

......................................................................................^Crake aborted!
Interrupt: 
Interrupted. Exiting...

#####  there are omitted error message with backtrace ##### 

Finished in 7433.238541s, 0.0116 runs/s, 0.0186 assertions/s.
Tasks: TOP => run

(See full trace by running task with --trace)
86 runs, 138 assertions, 0 failures, 0 errors, 0 skips

Add support for statement caching - Use query-parameters when `prepared_statements = true`?

Summary

According to the best practices on Cloud Spanner, it is recommended to use the query parameters to effectively use query plan cache as follows.

SELECT a.SingerId
FROM Albums AS a
WHERE a.AlbumTitle = @title AND a.ReleaseDate >= '2017-01-01'

When checking ruby-spanner-activerecord locally in my environment, following Ruby code did not generate query with parameters, but I would like to generate queries with parameters.

Sample.where(id: [1, 2, 3]).to_a
# => D, [2021-03-06T04:54:08.308896 #28539] DEBUG -- :   Sample Load (271.6ms)  SELECT `samples`.* FROM `samples` WHERE `samples`.`id` IN ('1', '2', '3')

Then, I have found that the following code disables prepared_statements.

def initialize connection, logger, connection_options, config
config[:prepared_statements] = false
super connection, logger, config
@connection_options = connection_options
end

Unlike traditional RDBMS, Cloud Spanner does NOT currently support a prepared statement. However, the objective of using the query parameters is the same; that is, to cache query plan and improve performance. I think the difference is to retrieve the cached query plan by some identifiers (Traditional RDBMS) or by full queries (Cloud Spanner).

Proposed Solution

In light of the above considerations, IMHO, I think it is intuitive to use query parameters when prepared_statements = true. When Cloud Spanner actually introduces prepared statements in the future, we can seamlessly migrate adapter to using real prepared statements.

References

https://cloud.google.com/spanner/docs/sql-best-practices?hl=en#query-parameters
https://www.slideshare.net/HammoudiSamir/cloud-spanner-78081604#25 # Sorry but written in Japanese

Any plans to publish alpha-version gems on rubygems.org?

At #8, I heard that Google Cloud Developers became the co-owners of https://rubygems.org/gems/activerecord-spanner-adapter.

Now, I am wondering when and how to migrate the gem on rubygems.org.

The reason behind this question is that I think releasing the alpha-version of this repository would increase developers' recognition of this repository and ease their development process. (e.g. install from rubygems.org, GitHub links from rubygems.org, and so on)

Also, it would ease the contribution process to this repository.

Create unique index for child id for interleaved tables

ActiveRecord requires primary keys to only contain one column. This is incompatible with interleaved tables in Cloud Spanner, as a child table must include all the columns of the primary key of the parent table in its own primary key, in addition to any of its own primary key columns. The Spanner ActiveRecord provider works around this by ensuring that the values of a child id is always globally unique within the table (as opposed to unique for each parent key), and uses only the child id as a primary key when fetching rows. This means that fetching a single child row using only the key value can cause a full table scan, as there is no index on only the child id column. The Spanner ActiveRecord provider should therefore:

  1. Automatically create a unique index on the child id column when creating interleaved tables in migrations.
  2. Document that existing interleaved tables that are to be used with ActiveRecord should also be altered to include a unique index on the child id column.
  3. Alter the existing interleaved tables sample to include the above.

Update schema versions and Information schema load not working with batched DDL statements.

Issue: The migration version will not be inserted in "schema_migrations" if any error occurs in the schema migration task. So next time on migration run migration task will not resume from the last failure but start from the first migration script or from if last version value is available in schema_migrations.

Rails migration doc for reference

Schema migration will create a batch of DDL statement and execute in one go. Related issues for this scenario.

  1. Any error occurs in the execution of one of the DDL statement then migration task is not able to figure out which migration file has this error based on GRPC error response received from the Google Spanner service, because of this it is a schema
  2. Information schema will not be available in certain cases if there is DQL or DML query executed using Model.
class AddTimestampToFirm < ActiveRecord::Migration[6.0]
  def change
    add_column :firm, :created_at, :time
    
    Firm.update_all(created_at: Time.now)
  end
end

Here at a time of the Firm.update_all(created_at: Time.now) call created_at is not available so it will throw an error.

Need to do is,
Translate error and find out last failed DDL statement and based on this find out-migration file version.

Support read-only transactions

Cloud Spanner has support for read-only transactions that can read data from a consistent snapshot at a specific timestamp. These transactions should also be usable with ActiveRecord.

[Policy Bot] found one or more issues with this repository.

Policy Bot found one or more issues with this repository.

  • Default branch is 'main'
  • Branch protection is enabled
  • Renovate bot is enabled
  • Merge commits disabled
  • There is a CODEOWNERS file
  • There is a valid LICENSE.md
  • There is a CODE_OF_CONDUCT.md
  • There is a CONTRIBUTING.md
  • There is a SECURITY.md

schema: handle lack of AUTO_INCREMENT in Cloud Spanner by UUID auto-generation

Cloud Spanner's server side lacks AUTO_INCREMENT support and requires that any field whose DDL statement contained an AUTO_INCREMENT should be manipulated by the client side and generate most ideally a UUID to avoid "hotspots" as per https://cloud.google.com/spanner/docs/schema-design#uuid_primary_key

This creates a complication however for apps that might be using the column key to peek for the next, or sorting by ID assuming that every ID will be sorted by magnitude, but also for every single INSERT, we'll need to cross reference with the table DDL statements to examine which field needs an ID automatically generated for it.

Check and retry `Session not found` errors

Each connection uses one session. That session will be garbage collected by the backend if it is not used for more than 60 minutes, but could also occasionally be cleaned up by the backend for other reasons. The ActiveRecord adapter should therefore retry any Session not found errors. The exact retry strategy depends on whether it happens during an explicit read/write transaction or not.

Acceptance test failure because of aborted transaction

See https://github.com/googleapis/ruby-spanner-activerecord/pull/98/checks?check_run_id=2996223338

  1) Error:
ActiveRecord::Associations::HasManyUsingInterleavedTest#test_successful_build_association:
Google::Cloud::AbortedError: 10:Transaction was aborted.. debug_error_string:***"created":"@1625555571.311616789","description":"Error received from peer ipv4:142.250.73.234:443","file":"src/core/lib/surface/call.cc","file_line":1066,"grpc_message":"Transaction was aborted.","grpc_status":10***
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/google-cloud-spanner-2.8.0/lib/google/cloud/spanner/results.rb:314:in `rescue in from_enum'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/google-cloud-spanner-2.8.0/lib/google/cloud/spanner/results.rb:305:in `from_enum'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/google-cloud-spanner-2.8.0/lib/google/cloud/spanner/results.rb:332:in `execute_query'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/google-cloud-spanner-2.8.0/lib/google/cloud/spanner/session.rb:331:in `execute_query'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/lib/activerecord_spanner_adapter/connection.rb:203:in `execute_query'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/lib/activerecord_spanner_adapter/base.rb:207:in `_execute_version_check'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/lib/activerecord_spanner_adapter/base.rb:166:in `_delete_row'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/lib/activerecord_spanner_adapter/base.rb:160:in `destroy_row'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/persistence.rb:535:in `destroy'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/callbacks.rb:309:in `block in destroy'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activesupport-6.0.3.7/lib/active_support/callbacks.rb:135:in `run_callbacks'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activesupport-6.0.3.7/lib/active_support/callbacks.rb:825:in `_run_destroy_callbacks'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/callbacks.rb:309:in `destroy'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/transactions.rb:310:in `block in destroy'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/transactions.rb:375:in `block in with_transaction_returning_status'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/connection_adapters/abstract/database_statements.rb:278:in `transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/lib/active_record/connection_adapters/spanner/database_statements.rb:111:in `transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/transactions.rb:212:in `transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/transactions.rb:366:in `with_transaction_returning_status'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/transactions.rb:310:in `destroy'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/lib/activerecord_spanner_adapter/base.rb:83:in `block in destroy'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/connection_adapters/abstract/database_statements.rb:280:in `block in transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/connection_adapters/abstract/transaction.rb:280:in `block in within_new_transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activesupport-6.0.3.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activesupport-6.0.3.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activesupport-6.0.3.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activesupport-6.0.3.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activesupport-6.0.3.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/connection_adapters/abstract/transaction.rb:278:in `within_new_transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/connection_adapters/abstract/database_statements.rb:280:in `transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/lib/active_record/connection_adapters/spanner/database_statements.rb:116:in `transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/transactions.rb:212:in `transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/transactions.rb:306:in `transaction'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/lib/activerecord_spanner_adapter/base.rb:82:in `destroy'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/relation.rb:544:in `each'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/relation.rb:544:in `destroy_all'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/vendor/bundle/ruby/3.0.0/gems/activerecord-6.0.3.7/lib/active_record/querying.rb:21:in `destroy_all'
    /home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/acceptance/cases/interleaved_associations/has_many_associations_using_interleaved_test.rb:36:in `teardown'

  2) Failure:
ActiveRecord::Associations::HasManyUsingInterleavedTest#test_create_and_delete_nested_associated_records [/home/runner/work/ruby-spanner-activerecord/ruby-spanner-activerecord/acceptance/cases/interleaved_associations/has_many_associations_using_interleaved_test.rb:138]:
Expected: 6
  Actual: 8

Use inlined BeginTransaction

As each connection has its own session, the BeginTransaction calls could be inlined with the first statement of a transaction, instead of executing a separate BeginTransaction RPC for each new transaction. This should reduce the number of round trips by one for most transactions.

2.1 - Add support for DDL batches in Connection API

Implement the following batching support (already supported by the Java Connection API):

START BATCH DDL;

-- Execute multiple DDL statements. These are automatically buffered in the connection.
CREATE TABLE Foo ...
CREATE TABLE Bar ...
CREATE INDEX Idx_Foo_ ...

-- This will execute all the buffered DDL statements
RUN BATCH

This feature can be used by applications in migrations and other DDL scripts to batch DDL statements together for better performance.

Sub step of #63

Add support for Cloud Spanner Emulator

I would like to use Cloud Spanner Emulator to develop this gem and to develop Rails application using gem. Although, there are limitations and differences, the emulator does not cost money 💸 and the separated environments are suited for local development.

https://cloud.google.com/spanner/docs/emulator

Then, I've found out that the current implementation of this library does not support emulator.
This is because Google::Cloud.spanner is used instead of Google::Cloud::Spanner.new. The former method pass the limited portion of parameters to the latter.

@spanners[database_path(config)] ||= Google::Cloud.spanner(
config[:project],
config[:credentials],
scope: config[:scope],
timeout: config[:timeout],
client_config: config[:client_config]&.symbolize_keys,
lib_name: "spanner-activerecord-adapter",
lib_version: ActiveRecordSpannerAdapter::VERSION
)

If we directly call Google::Cloud::Spanner.new(config), we can pass the emulator_host parameter in config, which enable developers to use Cloud Spanner Emulator.

https://github.com/googleapis/google-cloud-ruby/blob/06c73b3b4b09e5f4dded27b61662fe110fea57bb/google-cloud-spanner/lib/google/cloud/spanner.rb#L91-L101

Although, this breaks config[:project], config[:credentials] compatibility, I think keeping consistency with Google::Cloud::Spanner.new reduces maintenance cost.
Of course, If required, I can write backward-compatible code.

If the above strategy is O.K., I am willing to work on this issue.

feat: Add support for query hints

The ActiveRecord adapter allows a user to specify an optimizer hint for setting a stale read mode. It is however not possible to set a 'normal' query hint through the same method. This should also be added to the adapter.

Update README

  1. Correct typos
  2. Bring README up to date.

Related: b/186672491

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.