activerecord-beagle-turso 0.1.2 → 0.1.4

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: bca0371351d06b733b45c110457870093af9b82db4df224d51940d2da3f67289
4
- data.tar.gz: b80598ef59803b2380f55838cb05feb50c860c6df6e4628a5e646e1a98e19d74
3
+ metadata.gz: 954e05b945781cc01a630306c4cb5d9368ef5dcc54876269229afed57f3a56d1
4
+ data.tar.gz: e512726ed37adeeee5ce7fe6268d3ecda615c079a4b041cca7a1677cce9d55fd
5
5
  SHA512:
6
- metadata.gz: '068d1f9559e9aa7996f6f3c834b087ceb294db2869c76501201a5ace60d64dc6706e6f46cd58c43026f2b423c72d83ed013172c049ce284bebbcc4ea805dc821'
7
- data.tar.gz: 5c119de77b070ebd9270bb373cfcbc562ec0d3dd716d3b079622ecfdb8dc1c7303dbdd11b60f922672a8fdfd8f428d64c7c967098a73bd81d159545a0a162bfe
6
+ metadata.gz: e48728f8d4c61291db44090aab87067f31b76ef0503db34cdfcab18cb66e4d204a35b2ab7cdc3d6114ce555a49b347fdf88cc6406f5a08acb6cbc43e97d748e8
7
+ data.tar.gz: 70b9fb0e606a6e8e844a737d250016b800fdf21eb47e29ab3ead567821a5250ba95ff90a2e3dbaeb9283e1673624b3a8d31ed506bb0ce9e4217e5d5751e24965
@@ -126,7 +126,22 @@ module ActiveRecord
126
126
  # foreign_key_check) falls through to the real driver result instead
127
127
  # of a synthesized one -- failing loudly on a genuine future gap
128
128
  # rather than silently lying.
129
- BARE_PRAGMA_READ_REGEX = /\A\s*PRAGMA\s+(defer_foreign_keys|read_uncommitted)\s*\z/i
129
+ #
130
+ # The SQL-comment allowances on both ends are load-bearing, not
131
+ # cosmetic: with `config.active_record.query_log_tags_enabled = true`
132
+ # (the Rails app-generator default for development since 7.0) every
133
+ # statement arrives tagged -- `PRAGMA defer_foreign_keys
134
+ # /*application='MyApp'*/`. An `\z`-anchored match misses that, the
135
+ # synthesized default never fires, and the very crash this constant
136
+ # exists to prevent comes back: `add_foreign_key` (and every other
137
+ # alter_table schema change) dies with "query failed: incomplete
138
+ # input" while loading db/schema.rb. Tags can be prepended as well as
139
+ # appended (query_log_tags_format / prepend_comment), so allow both.
140
+ SQL_COMMENTS = %r{(?:\s*/\*.*?\*/)*}m
141
+ private_constant :SQL_COMMENTS
142
+
143
+ BARE_PRAGMA_READ_REGEX =
144
+ /\A#{SQL_COMMENTS}\s*PRAGMA\s+(defer_foreign_keys|read_uncommitted)\s*#{SQL_COMMENTS}\s*\z/im
130
145
  private_constant :BARE_PRAGMA_READ_REGEX
131
146
 
132
147
  # --- execution surface used by BeagleTursoAdapter#perform_query ---
@@ -191,6 +206,82 @@ module ActiveRecord
191
206
  end
192
207
 
193
208
  private
209
+ # Every table-listing question Rails asks (`tables`, `views`,
210
+ # `data_sources`, `table_exists?`, and through them the schema cache and
211
+ # the schema dumper) is built from this one string in
212
+ # SQLite3::SchemaStatements.
213
+ #
214
+ # beagle_turso's engine keeps a `__turso_internal_seq___turso_internal_
215
+ # autoincrement_<table>` bookkeeping table for each AUTOINCREMENT table.
216
+ # They are engine internals of exactly the kind Rails already excludes
217
+ # by name (`sqlite_sequence`, `sqlite_schema`), but Rails cannot know
218
+ # about them -- so without this filter `db:schema:dump` emits one
219
+ # `create_table "__turso_internal_seq_..."` block per table into
220
+ # db/schema.rb, and the next `db:schema:load` tries to create them for
221
+ # real.
222
+ def data_source_sql(name = nil, type: nil)
223
+ "#{super} AND name NOT LIKE '\\_\\_turso\\_internal\\_%' ESCAPE '\\'"
224
+ end
225
+
226
+ # A column definition in the DDL that carries a parenthesised type
227
+ # argument: `"price" decimal (10, 2) NOT NULL`, `a varchar (50)`. The
228
+ # name may be bare or quoted with ", ` or []; the type may be several
229
+ # words ("double precision"); the argument is one or two integers.
230
+ DECLARED_TYPE_REGEX = /
231
+ \A\s*
232
+ (?:"(?<name>[^"]*)" | `(?<name>[^`]*)` | \[(?<name>[^\]]*)\] | (?<name>\w+))
233
+ \s+
234
+ (?<type>[A-Za-z_][A-Za-z0-9_\ ]*?)
235
+ \s*\(\s*(?<args>\d+\s*(?:,\s*\d+)?)\s*\)
236
+ /x
237
+ private_constant :DECLARED_TYPE_REGEX
238
+
239
+ # Restore type arguments that beagle_turso's `PRAGMA table_info` drops.
240
+ #
241
+ # turso reports a column's declared type as the bare type name: a
242
+ # `decimal(10,2)` column comes back as `decimal`, `varchar(50)` as
243
+ # `varchar`, `datetime(6)` as `datetime`. Rails derives precision,
244
+ # scale and limit by parsing exactly that string, so all three silently
245
+ # become nil. Real SQLite returns the full declared type here, and the
246
+ # information is not lost on disk -- the CREATE TABLE in sqlite_master
247
+ # still says `decimal (10, 2)` -- so recover it from there.
248
+ #
249
+ # Left alone this is worse than cosmetic schema.rb churn: a dump emits
250
+ # `t.decimal "price"` with no precision/scale, and loading that dump
251
+ # builds a column whose values are no longer rounded to 2 decimal
252
+ # places. `super` already splits the DDL into per-column strings to
253
+ # recover COLLATE, AUTOINCREMENT and GENERATED ALWAYS AS for the same
254
+ # reason; this is the same trick for the type itself.
255
+ #
256
+ # Only fills in a missing argument -- a type that already arrived with
257
+ # one is left untouched, so this becomes an automatic no-op if turso
258
+ # starts reporting declared types in full.
259
+ def table_structure_with_collation(table_name, basic_structure)
260
+ columns = super
261
+ return columns unless columns.any? { |column| !column["type"].to_s.include?("(") }
262
+
263
+ declared = declared_column_types(table_name, columns.filter_map { |c| c["name"] })
264
+ return columns if declared.empty?
265
+
266
+ columns.each do |column|
267
+ next if column["type"].to_s.include?("(")
268
+
269
+ full_type = declared[column["name"]]
270
+ column["type"] = full_type if full_type
271
+ end
272
+ end
273
+
274
+ # Maps column name -> declared type with its argument normalised back
275
+ # to Rails' own spelling (`decimal (10, 2)` -> `decimal(10,2)`), which
276
+ # is what Rails' precision/scale/limit extraction expects to see.
277
+ def declared_column_types(table_name, column_names)
278
+ table_structure_sql(table_name, column_names).each_with_object({}) do |column_string, declared|
279
+ next unless (match = DECLARED_TYPE_REGEX.match(column_string))
280
+
281
+ declared[match[:name]] = "#{match[:type]}(#{match[:args].gsub(/\s+/, '')})"
282
+ end
283
+ end
284
+
194
285
  # The single seam. AbstractAdapter#raw_execute funnels every statement
195
286
  # here and expects an ActiveRecord::Result back, with the notification
196
287
  # payload's affected_rows/row_count filled in. cast_result (inherited)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module BeagleTurso
5
- VERSION = "0.1.2"
5
+ VERSION = "0.1.4"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-beagle-turso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - BeagleSoftwareUK
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-08 00:00:00.000000000 Z
11
+ date: 2026-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord