tina4ruby 3.13.53 → 3.13.55
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 +4 -4
- data/lib/tina4/migration.rb +67 -20
- data/lib/tina4/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad240221da05e1d22971216907aeffa2699c0bd5eae3b3e4b8aa0479bd2ee1e7
|
|
4
|
+
data.tar.gz: ef7821e3dc9d26d45b242fdaad3c8edb79960dcc9229012ec3a04298157e1336
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8ff611bd9c3c98c90036a44bf4bb03152e6e7eb280861bb9a9536fa79fbfae35e32502af36bf39a987598f5194bc5eb3bc8a8ff7608ef2aec220404a20d66b45
|
|
7
|
+
data.tar.gz: ccd42641cb4756e6e78d14249b7a11d792f8d65e076a59c2e6055010341628f2246e86b8708da4dd8bda6f998dbf8b2342baf854d44b141a4ad70c075f8ae222
|
data/lib/tina4/migration.rb
CHANGED
|
@@ -185,9 +185,9 @@ module Tina4
|
|
|
185
185
|
CREATE TABLE #{TRACKING_TABLE} (
|
|
186
186
|
id INTEGER NOT NULL PRIMARY KEY,
|
|
187
187
|
migration_name VARCHAR(500) NOT NULL UNIQUE,
|
|
188
|
-
description VARCHAR(500)
|
|
188
|
+
description VARCHAR(500),
|
|
189
189
|
batch INTEGER NOT NULL DEFAULT 1,
|
|
190
|
-
executed_at VARCHAR(50)
|
|
190
|
+
executed_at VARCHAR(50) NOT NULL,
|
|
191
191
|
passed INTEGER NOT NULL DEFAULT 1
|
|
192
192
|
)
|
|
193
193
|
SQL
|
|
@@ -211,16 +211,16 @@ module Tina4
|
|
|
211
211
|
when "mssql", "sqlserver" then "id INTEGER IDENTITY(1,1) PRIMARY KEY"
|
|
212
212
|
else "id INTEGER PRIMARY KEY AUTOINCREMENT" # sqlite (default)
|
|
213
213
|
end
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
# Canonical executed_at is a written VARCHAR(50) string (no
|
|
215
|
+
# CURRENT_TIMESTAMP default — a timestamp default on a VARCHAR is
|
|
216
|
+
# rejected by PostgreSQL/MySQL). recordMigration writes it explicitly.
|
|
217
217
|
@db.execute(<<~SQL)
|
|
218
218
|
CREATE TABLE #{TRACKING_TABLE} (
|
|
219
219
|
#{id_column},
|
|
220
|
-
migration_name VARCHAR(
|
|
221
|
-
description VARCHAR(
|
|
220
|
+
migration_name VARCHAR(500) NOT NULL UNIQUE,
|
|
221
|
+
description VARCHAR(500),
|
|
222
222
|
batch INTEGER NOT NULL DEFAULT 1,
|
|
223
|
-
|
|
223
|
+
executed_at VARCHAR(50) NOT NULL,
|
|
224
224
|
passed INTEGER NOT NULL DEFAULT 1
|
|
225
225
|
)
|
|
226
226
|
SQL
|
|
@@ -229,19 +229,34 @@ module Tina4
|
|
|
229
229
|
end
|
|
230
230
|
end
|
|
231
231
|
|
|
232
|
+
# Return a result row keyed by lower-case symbols. Firebird returns rows keyed
|
|
233
|
+
# by UPPERCASE string column names while SQLite/others return lower-case symbol
|
|
234
|
+
# keys, so the tracking-table reads below are normalised to one shape. Without
|
|
235
|
+
# this, `row[:migration_name]` is nil on Firebird and every applied migration
|
|
236
|
+
# is treated as pending and re-run.
|
|
237
|
+
def normalize_row(row)
|
|
238
|
+
return {} if row.nil?
|
|
239
|
+
|
|
240
|
+
source = row.respond_to?(:to_h) ? row.to_h : row
|
|
241
|
+
source.each_with_object({}) { |(k, v), h| h[k.to_s.downcase.to_sym] = v }
|
|
242
|
+
end
|
|
243
|
+
|
|
232
244
|
def completed_migrations
|
|
233
245
|
result = @db.fetch("SELECT migration_name FROM #{TRACKING_TABLE} WHERE passed = 1 ORDER BY id")
|
|
234
|
-
result.map { |r| r[:migration_name] }
|
|
246
|
+
result.map { |r| normalize_row(r)[:migration_name] }
|
|
235
247
|
end
|
|
236
248
|
|
|
237
249
|
def completed_migrations_with_batch
|
|
238
250
|
result = @db.fetch("SELECT id, migration_name, batch FROM #{TRACKING_TABLE} WHERE passed = 1 ORDER BY id")
|
|
239
|
-
result.map
|
|
251
|
+
result.map do |r|
|
|
252
|
+
row = normalize_row(r)
|
|
253
|
+
{ id: row[:id], migration_name: row[:migration_name], batch: row[:batch] }
|
|
254
|
+
end
|
|
240
255
|
end
|
|
241
256
|
|
|
242
257
|
def next_batch_number
|
|
243
|
-
result = @db.fetch_one("SELECT MAX(batch) as max_batch FROM #{TRACKING_TABLE} WHERE passed = 1")
|
|
244
|
-
(result
|
|
258
|
+
result = normalize_row(@db.fetch_one("SELECT MAX(batch) as max_batch FROM #{TRACKING_TABLE} WHERE passed = 1"))
|
|
259
|
+
(result[:max_batch] ? result[:max_batch].to_i : 0) + 1
|
|
245
260
|
end
|
|
246
261
|
|
|
247
262
|
def pending_migrations
|
|
@@ -479,12 +494,22 @@ module Tina4
|
|
|
479
494
|
next
|
|
480
495
|
end
|
|
481
496
|
|
|
482
|
-
# Statement delimiter — only reached outside blocks/comments/strings.
|
|
497
|
+
# Statement delimiter — only reached outside blocks/comments/strings. A
|
|
498
|
+
# SET TERM directive switches the active terminator and is consumed
|
|
499
|
+
# (never emitted); any other completed statement is collected.
|
|
483
500
|
if !delimiter.empty? && sql[i, dlen] == delimiter
|
|
501
|
+
i += dlen
|
|
484
502
|
stmt = current.strip
|
|
485
|
-
statements << stmt unless stmt.empty?
|
|
486
503
|
current = +""
|
|
487
|
-
|
|
504
|
+
unless stmt.empty?
|
|
505
|
+
new_term = parse_set_term(stmt)
|
|
506
|
+
if new_term
|
|
507
|
+
delimiter = new_term
|
|
508
|
+
dlen = delimiter.length
|
|
509
|
+
else
|
|
510
|
+
statements << stmt
|
|
511
|
+
end
|
|
512
|
+
end
|
|
488
513
|
next
|
|
489
514
|
end
|
|
490
515
|
|
|
@@ -492,11 +517,30 @@ module Tina4
|
|
|
492
517
|
i += 1
|
|
493
518
|
end
|
|
494
519
|
|
|
520
|
+
# Trailing statement (may not end with a delimiter). A trailing SET TERM
|
|
521
|
+
# directive is a no-op — consume it, don't emit it.
|
|
495
522
|
stmt = current.strip
|
|
496
|
-
statements << stmt unless stmt.empty?
|
|
523
|
+
statements << stmt unless stmt.empty? || parse_set_term(stmt)
|
|
497
524
|
statements
|
|
498
525
|
end
|
|
499
526
|
|
|
527
|
+
# Return the new terminator from a `SET TERM <new> <current>` directive, or
|
|
528
|
+
# nil when +statement+ is not a SET TERM directive.
|
|
529
|
+
#
|
|
530
|
+
# SET TERM is a script-level directive (recognised by isql and other
|
|
531
|
+
# InterBase/Firebird tooling, not run by the engine) that changes the
|
|
532
|
+
# terminator separating statements. Recognising it lets a statement whose own
|
|
533
|
+
# body contains the default ";" terminator — a trigger, stored procedure or
|
|
534
|
+
# EXECUTE BLOCK — be kept intact rather than split on those inner ";". The
|
|
535
|
+
# terminator may be more than one character (e.g. "!!").
|
|
536
|
+
#
|
|
537
|
+
# @param statement [String] a single, already-stripped statement
|
|
538
|
+
# @return [String, nil] the new terminator, or nil when not a SET TERM directive
|
|
539
|
+
def parse_set_term(statement)
|
|
540
|
+
m = statement.strip.match(/\ASET\s+TERM\s+(\S+)\z/i)
|
|
541
|
+
m && m[1]
|
|
542
|
+
end
|
|
543
|
+
|
|
500
544
|
def execute_sql_file(file)
|
|
501
545
|
sql = File.read(file)
|
|
502
546
|
statements = split_sql_statements(sql)
|
|
@@ -584,6 +628,9 @@ module Tina4
|
|
|
584
628
|
# Extract description from filename (strip numeric prefix and extension)
|
|
585
629
|
stem = File.basename(name, File.extname(name))
|
|
586
630
|
desc = stem.sub(/\A\d+_/, "").tr("_", " ")
|
|
631
|
+
# executed_at is a written VARCHAR(50) string (canonical shape has no
|
|
632
|
+
# CURRENT_TIMESTAMP default), ISO-8601 UTC. strftime avoids a require "time".
|
|
633
|
+
executed_at = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
587
634
|
if firebird?
|
|
588
635
|
# Firebird: generate ID from sequence
|
|
589
636
|
row = @db.fetch_one(
|
|
@@ -591,13 +638,13 @@ module Tina4
|
|
|
591
638
|
)
|
|
592
639
|
next_id = row ? (row[:NEXT_ID] || row[:next_id] || 1).to_i : 1
|
|
593
640
|
@db.execute(
|
|
594
|
-
"INSERT INTO #{TRACKING_TABLE} (id, migration_name, description, batch, passed) VALUES (?, ?, ?, ?, ?)",
|
|
595
|
-
[next_id, name, desc, batch, passed]
|
|
641
|
+
"INSERT INTO #{TRACKING_TABLE} (id, migration_name, description, batch, executed_at, passed) VALUES (?, ?, ?, ?, ?, ?)",
|
|
642
|
+
[next_id, name, desc, batch, executed_at, passed]
|
|
596
643
|
)
|
|
597
644
|
else
|
|
598
645
|
@db.execute(
|
|
599
|
-
"INSERT INTO #{TRACKING_TABLE} (migration_name, description, batch, passed) VALUES (?, ?, ?, ?)",
|
|
600
|
-
[name, desc, batch, passed]
|
|
646
|
+
"INSERT INTO #{TRACKING_TABLE} (migration_name, description, batch, executed_at, passed) VALUES (?, ?, ?, ?, ?)",
|
|
647
|
+
[name, desc, batch, executed_at, passed]
|
|
601
648
|
)
|
|
602
649
|
end
|
|
603
650
|
end
|
data/lib/tina4/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tina4ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.13.
|
|
4
|
+
version: 3.13.55
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tina4 Team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|