tarantool-rails 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80ffc3cc37871dc29b1b3fb3b9da05958369823bca8e9685ed6f341ebbb9212e
4
- data.tar.gz: e8428bdd33eb1e8ecb1107bd3b8eb657b8906f0220325048aa1bea8402303a69
3
+ metadata.gz: 30e777d2be6062e333e01fa5ab1e50fc2ccab417e19ae4513dddf8a5b8f2bd8f
4
+ data.tar.gz: 72c8fdfd334c5d3da9b62313e90e92650e7b045596d57409aff7a02e2dff8c85
5
5
  SHA512:
6
- metadata.gz: d10aff0d221c3ab0c395a6e1dea3e106c50befda2dd38425f6ac2e926158350ac2859aa39bee54335e21d4e78ac679fc6e291cc2576b31768616006e820084c7
7
- data.tar.gz: 19c895b419c10098ea3d347848f74d216d29b76206630d6979f0ae14ad8d59f0b0a50274c51ea10b854d89fef50a1ab9716aa7c597481f4f2f7dd287093487e4
6
+ metadata.gz: 10cd6a546bb3298f10b39a44a3fec2f79189c300e9152e0a1eaad79f9350e868b0d84caae77e77e222f2f03cc989070674cbde5b61c45a023b70cf1679636f72
7
+ data.tar.gz: 38f7446ec5667c71a8717e84bf4b77b2763288d8f011be423867796a982e85844651ad10296961644e8a0df7716c443b09aba827da452aa652110a1b77bed59e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 (2026-10-18)
4
+
5
+ - `config.tarantool.instrumenter` replaces `ActiveSupport::Notifications` as the pool instrumenter, for chaining
6
+ tarantool-opentelemetry.
7
+ - Depends on `tarantool-client ~> 0.3` and `tarantool-schema ~> 0.3`; `tarantool:schema:apply` grants what the schema declares.
8
+ - The schema rake tasks no longer define helper methods and a constant on `Object`.
9
+
3
10
  ## 0.2.0 (2026-10-17)
4
11
 
5
12
  - `tarantool:schema:dump` writes the live schema to `config/tarantool_schema.rb` (`FORCE=1` to overwrite,
data/README.md CHANGED
@@ -67,6 +67,14 @@ can run; the first model operation then raises `Tarantool::Rails::Error`.
67
67
  password).
68
68
  - `Tarantool::Rails.pool` is one `Tarantool::Client::Pool` per process, built on first use with
69
69
  `instrumenter: ActiveSupport::Notifications`. After `fork` the pool reopens its connections on its own.
70
+ `config.tarantool.instrumenter` replaces the instrumenter; the log subscriber still needs the events on
71
+ `ActiveSupport::Notifications`, so chain it:
72
+
73
+ ```ruby
74
+ # config/initializers/tarantool.rb
75
+ Rails.application.config.tarantool.instrumenter =
76
+ Tarantool::OpenTelemetry::Instrumenter.new(instrumenter: ActiveSupport::Notifications)
77
+ ```
70
78
  - `Tarantool::Rails.storage` is a `Storage::Box` (or `Storage::Crud`) over the pool, and
71
79
  `Tarantool::Model.default_storage` is set so every model without a storage of its own uses it. Nothing
72
80
  connects until a model is used.
@@ -118,7 +126,7 @@ end
118
126
  | Task | |
119
127
  |---|---|
120
128
  | `rails tarantool:schema:plan` | prints what `apply` would create; drift raises `MismatchError` with the diff |
121
- | `rails tarantool:schema:apply` | creates the missing spaces and indexes and prints them; never drops |
129
+ | `rails tarantool:schema:apply` | creates the missing spaces, indexes and grants and prints them; never drops |
122
130
  | `rails tarantool:schema:check` | for CI: exits 1 and prints `pending: ...` when anything would be created, 0 when live equals declared |
123
131
  | `rails tarantool:schema:dump` | writes the live schema to `config/tarantool_schema.rb` for bootstrapping; refuses to overwrite unless `FORCE=1`; `dump[users,codes]` limits the spaces |
124
132
 
@@ -201,6 +209,8 @@ gem must be in the Gemfile.
201
209
  `Tarantool::Rails::Configuration`, `Tarantool::Rails::LogSubscriber`, `Tarantool::Rails::Error`
202
210
  (descends from `Tarantool::Error`), the rake tasks and the generators.
203
211
 
212
+ RBS signatures for this API ship with the gem in `sig/`.
213
+
204
214
  Everything else, including anything tagged `@api private` in its source comment, is an implementation detail
205
215
  and may change in any release.
206
216
 
@@ -5,4 +5,5 @@ Tarantool::Rails.schema = Tarantool::Schema::Definition.new do
5
5
  # ensure_space :users,
6
6
  # format: [{ name: :id, type: :unsigned }, { name: :email, type: :string }],
7
7
  # indexes: [{ name: :primary, parts: [:id], sequence: true }, { name: :email, parts: [:email] }]
8
+ # grant :app, %i[read write], on: :users
8
9
  end
@@ -22,6 +22,8 @@ module Tarantool
22
22
  }.freeze
23
23
  ID = Field.new(name: 'id', attribute_type: ':integer', field_type: 'unsigned', nullable: false)
24
24
  SCHEMA_PATH = 'config/tarantool_schema.rb'
25
+ SCHEMA_END = /^end\s*\z/
26
+ LINE_START = /^/
25
27
 
26
28
  source_root File.expand_path('templates', __dir__)
27
29
 
@@ -40,7 +42,7 @@ module Tarantool
40
42
  def add_space_to_schema
41
43
  return if options[:skip_schema] || !File.exist?(File.join(destination_root, SCHEMA_PATH))
42
44
 
43
- inject_into_file SCHEMA_PATH, space_declaration, before: /^end\s*\z/
45
+ inject_into_file SCHEMA_PATH, space_declaration, before: SCHEMA_END
44
46
  end
45
47
 
46
48
  private
@@ -70,7 +72,7 @@ module Tarantool
70
72
  ' ],', ' indexes: [',
71
73
  " { name: :primary, parts: [:#{model_fields.first.name}]#{sequence} }", ' ]']
72
74
 
73
- "\n#{lines.join("\n").gsub(/^/, ' ')}\n"
75
+ "\n#{lines.join("\n").gsub(LINE_START, ' ')}\n"
74
76
  end
75
77
  end
76
78
  end
@@ -17,7 +17,7 @@ module Tarantool
17
17
  def filtered(key, value)
18
18
  case key
19
19
  when :client_options then value.key?(:password) ? value.merge(password: '[FILTERED]') : value
20
- when :admin_uri then value&.sub(%r{:[^:@/]*@}, ':[FILTERED]@')
20
+ when :admin_uri then value&.sub(Configuration::URI_PASSWORD, ':[FILTERED]@')
21
21
  else value
22
22
  end
23
23
  end
@@ -30,6 +30,7 @@ module Tarantool
30
30
  KEYS = (CLIENT_KEYS + %i[addresses address read write storage crud admin_uri]).freeze
31
31
  CRUD_KEYS = %i[primary_index read write timeout_margin].freeze
32
32
  STORAGES = %i[box crud].freeze
33
+ URI_PASSWORD = %r{:[^:@/]*@}
33
34
 
34
35
  class << self
35
36
  def from_hash(hash)
@@ -10,6 +10,7 @@ module Tarantool
10
10
  # A missing config/tarantool.yml is not an error at boot: the install generator has to be able to run.
11
11
  initializer 'tarantool.configuration' do |app|
12
12
  Tarantool::Rails.schema_path = app.config.tarantool.schema_path || app.root.join('config/tarantool_schema.rb')
13
+ Tarantool::Rails.instrumenter = app.config.tarantool.instrumenter
13
14
  next unless app.root.join('config/tarantool.yml').exist?
14
15
 
15
16
  section = app.config_for(:tarantool)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tarantool
4
+ module Rails
5
+ # Helpers behind the tarantool:schema rake tasks.
6
+ # @api private
7
+ module SchemaTasks
8
+ # Task arguments are one String: rails "tarantool:schema:apply[add_field]", "tarantool:schema:dump[users,codes]".
9
+ NAME_SEPARATOR = /[\s,]+/
10
+
11
+ module_function
12
+
13
+ def names(argument) = argument.to_s.split(NAME_SEPARATOR).reject(&:empty?)
14
+
15
+ def dump(path, only)
16
+ abort "#{path} exists; set FORCE=1 to overwrite" if File.exist?(path) && ENV['FORCE'].to_s.empty?
17
+
18
+ definition = Tarantool::Rails.admin_client do |client|
19
+ Tarantool::Schema::Definition.from_live(client, only: only.empty? ? nil : only)
20
+ end
21
+ File.write(path, "# frozen_string_literal: true\n\nTarantool::Rails.schema = #{definition.to_ruby}")
22
+ puts path
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,37 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Task arguments are one String: rails "tarantool:schema:apply[add_field]", "tarantool:schema:dump[users,codes]".
4
- TARANTOOL_SCHEMA_NAME_SEPARATOR = /[\s,]+/
5
-
6
- def tarantool_schema_names(argument) = argument.to_s.split(TARANTOOL_SCHEMA_NAME_SEPARATOR).reject(&:empty?)
7
-
8
- def tarantool_schema_dump(path, only)
9
- abort "#{path} exists; set FORCE=1 to overwrite" if File.exist?(path) && ENV['FORCE'].to_s.empty?
10
-
11
- definition = Tarantool::Rails.admin_client do |client|
12
- Tarantool::Schema::Definition.from_live(client, only: only.empty? ? nil : only)
13
- end
14
- File.write(path, "# frozen_string_literal: true\n\nTarantool::Rails.schema = #{definition.to_ruby}")
15
- puts path
16
- end
17
-
18
3
  namespace :tarantool do
19
4
  namespace :schema do
20
5
  desc 'Print what tarantool:schema:apply would create; fail on drift'
21
6
  task :plan, [:alter] => :environment do |_task, args|
22
- alter = tarantool_schema_names(args[:alter]).map(&:to_sym)
7
+ alter = Tarantool::Rails::SchemaTasks.names(args[:alter]).map(&:to_sym)
23
8
  Tarantool::Rails.admin_client { |client| puts Tarantool::Rails.schema.plan(client, alter:) }
24
9
  end
25
10
 
26
11
  desc 'Create missing Tarantool spaces and indexes; fail on drift'
27
12
  task :apply, [:alter] => :environment do |_task, args|
28
- alter = tarantool_schema_names(args[:alter]).map(&:to_sym)
13
+ alter = Tarantool::Rails::SchemaTasks.names(args[:alter]).map(&:to_sym)
29
14
  Tarantool::Rails.admin_client { |client| puts Tarantool::Rails.schema.apply(client, alter:) }
30
15
  end
31
16
 
32
17
  desc 'Fail unless the live schema equals the declaration, for CI'
33
18
  task :check, [:alter] => :environment do |_task, args|
34
- alter = tarantool_schema_names(args[:alter]).map(&:to_sym)
19
+ alter = Tarantool::Rails::SchemaTasks.names(args[:alter]).map(&:to_sym)
35
20
  pending = Tarantool::Rails.admin_client { |client| Tarantool::Rails.schema.plan(client, alter:) }
36
21
  next if pending.empty?
37
22
 
@@ -41,7 +26,8 @@ namespace :tarantool do
41
26
 
42
27
  desc 'Write the live schema to config/tarantool_schema.rb (FORCE=1 to overwrite; spaces as [users,codes])'
43
28
  task :dump, [:only] => :environment do |_task, args|
44
- tarantool_schema_dump(Tarantool::Rails.schema_path.to_s, tarantool_schema_names(args[:only]))
29
+ Tarantool::Rails::SchemaTasks.dump(Tarantool::Rails.schema_path.to_s,
30
+ Tarantool::Rails::SchemaTasks.names(args[:only]))
45
31
  end
46
32
  end
47
33
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Tarantool
4
4
  module Rails
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
@@ -10,6 +10,7 @@ require_relative 'rails/errors'
10
10
  require_relative 'rails/configuration'
11
11
  require_relative 'rails/log_subscriber'
12
12
  require_relative 'rails/controller_runtime'
13
+ require_relative 'rails/schema_tasks'
13
14
  require_relative 'rails/railtie' if defined?(Rails::Railtie)
14
15
 
15
16
  module Tarantool
@@ -21,7 +22,13 @@ module Tarantool
21
22
 
22
23
  class << self
23
24
  attr_accessor :config, :schema_path
24
- attr_writer :schema
25
+ attr_writer :schema, :instrumenter
26
+
27
+ # What the pool reports requests to; the log subscriber listens to ActiveSupport::Notifications, so an
28
+ # instrumenter of your own should chain it (tarantool-opentelemetry's does with `instrumenter:`).
29
+ def instrumenter
30
+ @instrumenter || ActiveSupport::Notifications
31
+ end
25
32
 
26
33
  def pool
27
34
  LOCK.synchronize { @pool ||= build_pool }
@@ -69,8 +76,7 @@ module Tarantool
69
76
  end
70
77
 
71
78
  def build_pool
72
- Tarantool::Client::Pool.new(configured.addresses, **configured.client_options,
73
- instrumenter: ActiveSupport::Notifications)
79
+ Tarantool::Client::Pool.new(configured.addresses, **configured.client_options, instrumenter:)
74
80
  end
75
81
 
76
82
  def build_storage
@@ -0,0 +1,59 @@
1
+ module Tarantool
2
+ # Rails integration: configuration from config/tarantool.yml, one Pool per process, models on it, log lines,
3
+ # schema rake tasks and generators.
4
+ module Rails
5
+ VERSION: String
6
+
7
+ def self.config: () -> Configuration?
8
+ def self.config=: (Configuration? config) -> void
9
+ def self.schema_path: () -> (String | Pathname)?
10
+ def self.schema_path=: ((String | Pathname)? path) -> void
11
+ # Loaded from schema_path on first use; the file assigns it.
12
+ def self.schema: () -> Tarantool::Schema::Definition
13
+ def self.schema=: (Tarantool::Schema::Definition? schema) -> void
14
+ # ActiveSupport::Notifications unless configured.
15
+ def self.instrumenter: () -> Tarantool::Client::_Instrumenter
16
+ def self.instrumenter=: (Tarantool::Client::_Instrumenter? instrumenter) -> void
17
+ def self.pool: () -> Tarantool::Client::Pool
18
+ def self.storage: () -> (Tarantool::Model::Storage::Box | Tarantool::Model::Storage::Crud)
19
+ def self.admin_client: [T] () { (Tarantool::Client client) -> T } -> T
20
+ def self.use_default_storage!: () -> void
21
+ def self.disconnect!: () -> void
22
+
23
+ class Error < Tarantool::Error
24
+ end
25
+
26
+ # One environment section of config/tarantool.yml; inspect and to_s hide the password.
27
+ class Configuration < Data
28
+ attr_reader addresses: Array[String]
29
+ attr_reader client_options: Hash[Symbol, untyped]
30
+ attr_reader storage: :box | :crud
31
+ attr_reader read: Hash[Symbol, untyped]
32
+ attr_reader write: Hash[Symbol, untyped]
33
+ attr_reader crud: Hash[Symbol, untyped]
34
+ attr_reader admin_uri: String?
35
+
36
+ # The Hash config_for returns (an ActiveSupport::OrderedOptions is a Hash); unknown keys raise ArgumentError.
37
+ def self.from_hash: (Hash[Symbol | String, untyped] hash) -> Configuration
38
+ def inspect: () -> String
39
+ def to_s: () -> String
40
+ end
41
+
42
+ # ActiveRecord-style log lines for the client's events (an ActiveSupport::LogSubscriber); the time spent in
43
+ # requests is accumulated per thread for the controller log.
44
+ class LogSubscriber
45
+ def self.runtime: () -> Float
46
+ def self.runtime=: (Float value) -> void
47
+ def self.reset_runtime: () -> Float
48
+
49
+ # Each takes an ActiveSupport::Notifications::Event.
50
+ def request: (untyped event) -> void
51
+ def disconnect: (untyped event) -> void
52
+ def reconnect: (untyped event) -> void
53
+ def reconnect_failed: (untyped event) -> void
54
+ def fork: (untyped event) -> void
55
+ def role_change: (untyped event) -> void
56
+ def shutdown: (untyped event) -> void
57
+ end
58
+ end
59
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tarantool-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Starlexxx
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-17 00:00:00.000000000 Z
11
+ date: 2026-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.2'
39
+ version: '0.3'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.2'
46
+ version: '0.3'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: tarantool-model
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -64,14 +64,14 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '0.2'
67
+ version: '0.3'
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0.2'
74
+ version: '0.3'
75
75
  description: config/tarantool.yml per environment, one connection pool per process,
76
76
  models on it without an initializer, ActiveRecord-style log lines, schema rake tasks
77
77
  and generators.
@@ -95,8 +95,10 @@ files:
95
95
  - lib/tarantool/rails/errors.rb
96
96
  - lib/tarantool/rails/log_subscriber.rb
97
97
  - lib/tarantool/rails/railtie.rb
98
+ - lib/tarantool/rails/schema_tasks.rb
98
99
  - lib/tarantool/rails/tasks/schema.rake
99
100
  - lib/tarantool/rails/version.rb
101
+ - sig/tarantool/rails.rbs
100
102
  homepage: https://github.com/Starlexxx/tarantool-ruby
101
103
  licenses:
102
104
  - MIT