activerecord-beagle-turso 0.1.3 → 0.1.5
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96e5e44a6be08be7733d3f7ea9590e6577826c43d8ecffe178f6bb6314d3396c
|
|
4
|
+
data.tar.gz: 66627c1ff6245cb9f44180c6152020248d49f58722359c7070ce883a9cbe4ed2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cc94306cead989dba2cf18789880c63cc4eb27b973812bec9f807fbbdf40b81baef90edcc512d099a90c2955427ed56582c51c0dd1d7fb6fc1439e973dfbbd5f
|
|
7
|
+
data.tar.gz: d15c112f354343e61bda83c8f146603ae0aa1c6da19381e158eb01ce84ee487f82e67e775d416328196d5c2cf7a4f25872954219a63f75181535318681d806a3
|
data/README.md
CHANGED
|
@@ -94,7 +94,7 @@ All three default their `connection` argument to `ActiveRecord::Base.connection`
|
|
|
94
94
|
so `Beagle::Turso::SyncManager.sync!` alone is the usual call. Calling any of
|
|
95
95
|
them against a **local-only** connection (no `remote_url:`/`auth_token:` in
|
|
96
96
|
`database.yml`) raises `Beagle::Turso::SyncManager::NotSyncedError` — a
|
|
97
|
-
distinct, rescuable type — rather than the driver's
|
|
97
|
+
distinct, rescuable type — rather than the driver's own `Beagle::Turso::NotSyncedError`.
|
|
98
98
|
|
|
99
99
|
To sync on a timer, wire
|
|
100
100
|
`ActiveRecord::ConnectionAdapters::BeagleTurso::SyncJob` (a thin delegator to
|
|
@@ -46,23 +46,14 @@ module Beagle
|
|
|
46
46
|
module SyncManager
|
|
47
47
|
# Raised by +push!+/+pull!+/+sync!+ when the given connection is
|
|
48
48
|
# local-only (its database.yml entry has no +remote_url+/+auth_token+,
|
|
49
|
-
# so BeagleTursoAdapter opened it via +Database.open_local+). The
|
|
50
|
-
#
|
|
51
|
-
# this (
|
|
52
|
-
# it as this distinct, documented type so callers can rescue it
|
|
53
|
-
# specifically instead of matching on the driver's message text. A
|
|
49
|
+
# so BeagleTursoAdapter opened it via +Database.open_local+). The driver
|
|
50
|
+
# raises Beagle::Turso::NotSyncedError for this; SyncManager re-raises it
|
|
51
|
+
# as this type (kept for compatibility) with a database.yml hint. A
|
|
54
52
|
# genuine sync failure against a real remote (network error, auth
|
|
55
|
-
# failure, etc.) is NOT reclassified -- it propagates as
|
|
56
|
-
#
|
|
53
|
+
# failure, etc.) is NOT reclassified -- it propagates as
|
|
54
|
+
# Beagle::Turso::SyncError (or another Beagle::Turso::Error), unchanged.
|
|
57
55
|
class NotSyncedError < StandardError; end
|
|
58
56
|
|
|
59
|
-
# Matches only the driver's local-only wording (see
|
|
60
|
-
# beagle_turso_core's `Error::Sync` in `Database::push`/`Database::pull`)
|
|
61
|
-
# so a real sync failure -- which also surfaces as a RuntimeError, just
|
|
62
|
-
# with different text -- is never misreported as "not synced".
|
|
63
|
-
LOCAL_ONLY_MESSAGE_REGEX = /on a local-only database/i
|
|
64
|
-
private_constant :LOCAL_ONLY_MESSAGE_REGEX
|
|
65
|
-
|
|
66
57
|
module_function
|
|
67
58
|
|
|
68
59
|
# Push this connection's local writes to its remote Turso database.
|
|
@@ -88,9 +79,7 @@ module Beagle
|
|
|
88
79
|
|
|
89
80
|
def reraise_local_only
|
|
90
81
|
yield
|
|
91
|
-
rescue
|
|
92
|
-
raise e unless LOCAL_ONLY_MESSAGE_REGEX.match?(e.message)
|
|
93
|
-
|
|
82
|
+
rescue Beagle::Turso::NotSyncedError => e
|
|
94
83
|
raise NotSyncedError,
|
|
95
84
|
"#{e.message} -- this connection is local-only; configure remote_url: " \
|
|
96
85
|
"and auth_token: in database.yml to enable sync"
|
|
@@ -223,6 +223,65 @@ module ActiveRecord
|
|
|
223
223
|
"#{super} AND name NOT LIKE '\\_\\_turso\\_internal\\_%' ESCAPE '\\'"
|
|
224
224
|
end
|
|
225
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
|
+
|
|
226
285
|
# The single seam. AbstractAdapter#raw_execute funnels every statement
|
|
227
286
|
# here and expects an ActiveRecord::Result back, with the notification
|
|
228
287
|
# payload's affected_rows/row_count filled in. cast_result (inherited)
|
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.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- BeagleSoftwareUK
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -30,14 +30,14 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0.
|
|
33
|
+
version: '0.2'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0.
|
|
40
|
+
version: '0.2'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: sqlite3
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|