tina4ruby 3.13.125 → 3.13.127
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/dev_admin.rb +3 -1
- data/lib/tina4/drivers/firebird_driver.rb +17 -11
- data/lib/tina4/drivers/mssql_driver.rb +14 -8
- data/lib/tina4/seeder.rb +65 -6
- data/lib/tina4/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0765c0228c99d3b8d5e26124c0afe5079ccc9ac675a3f067fc38e2e829bded7f
|
|
4
|
+
data.tar.gz: 6134c34d7f1ea98ea558862e1f98dbb0532b2d6fb3156b8bad5b9e129e362475
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0979843fa3654d0c48c62c19bbc8e5615a7b4b582286e14b3c517b76f3d9a50eb3246feb125b365b071c2c76adf7cdcbf93f802a576d75e5959d337cd19543c0'
|
|
7
|
+
data.tar.gz: f5ba6720f96dee12b2b7d751282fba8835771a11b368afafd64bf311c9ca1d8bf8501fd3b28493dd42126dfb0b4159a4c50a407422d5b8f63b680b7b67dbe038
|
data/lib/tina4/dev_admin.rb
CHANGED
|
@@ -1385,7 +1385,9 @@ module Tina4
|
|
|
1385
1385
|
# the closure, not a dead keyword.
|
|
1386
1386
|
fake = Tina4::FakeData.new(seed: seed)
|
|
1387
1387
|
field_map = Tina4._normalize_columns(db.columns(table_name)).each_with_object({}) do |(col_name, type_sym), map|
|
|
1388
|
-
|
|
1388
|
+
# Thread the TABLE name so a generic name column on a product-ish
|
|
1389
|
+
# table seeds a product name (parity with the seed_table path).
|
|
1390
|
+
map[col_name] = -> { fake.for_field({ type: type_sym }, col_name, table_name) }
|
|
1389
1391
|
end
|
|
1390
1392
|
# Delegate to the shared resilient seed_table helper so the endpoint
|
|
1391
1393
|
# gets the exact same per-row wrap (P1) — no unhandled row failure can
|
|
@@ -230,18 +230,24 @@ module Tina4
|
|
|
230
230
|
rows.map { |row| decode_blobs(symbolize_keys(row)) }
|
|
231
231
|
end
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
233
|
+
# Translate SQLite-canonical SQL to Firebird at APPLY time, mirroring the
|
|
234
|
+
# Python master's firebird.py _translate_sql: strip AUTOINCREMENT (Firebird
|
|
235
|
+
# uses generators), bare TRUE/FALSE -> 1/0 (Firebird has no boolean type; a
|
|
236
|
+
# TRUE/FALSE INSIDE a string literal is data and is left untouched), rewrite
|
|
237
|
+
# the types Firebird rejects -- TEXT -> BLOB SUB_TYPE TEXT (-607), REAL ->
|
|
238
|
+
# DOUBLE PRECISION -- and drop CREATE TABLE IF NOT EXISTS. Every helper only
|
|
239
|
+
# touches DDL keywords or bare boolean tokens, so a plain
|
|
240
|
+
# INSERT/UPDATE/DELETE/SELECT is returned untouched. This is what lets a
|
|
241
|
+
# REALLY-generated migration (id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
242
|
+
# bio TEXT, price REAL) apply on Firebird instead of raising -607/-104.
|
|
243
|
+
def translate_sql(sql)
|
|
243
244
|
sql = Tina4::SQLTranslator.auto_increment_syntax(sql, "firebird")
|
|
244
|
-
sql = Tina4::SQLTranslator.
|
|
245
|
+
sql = Tina4::SQLTranslator.boolean_to_int(sql)
|
|
246
|
+
Tina4::SQLTranslator.ddl_types(sql, "firebird")
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def execute(sql, params = [])
|
|
250
|
+
sql = translate_sql(sql)
|
|
245
251
|
result = with_reconnect do
|
|
246
252
|
if params.empty?
|
|
247
253
|
@connection.execute(sql)
|
|
@@ -58,15 +58,21 @@ module Tina4
|
|
|
58
58
|
rows
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
61
|
+
# Translate SQLite-canonical SQL to T-SQL at APPLY time, mirroring the
|
|
62
|
+
# Python master's mssql.py _translate_sql: AUTOINCREMENT -> IDENTITY(1,1),
|
|
63
|
+
# bare TRUE/FALSE -> 1/0 (MSSQL has BIT, not a boolean type; a TRUE/FALSE
|
|
64
|
+
# INSIDE a string literal is data and is left untouched), strip CREATE TABLE
|
|
65
|
+
# IF NOT EXISTS (not T-SQL) and map TIMESTAMP -> DATETIME2 (MSSQL's TIMESTAMP
|
|
66
|
+
# is a rowversion). Every helper only touches DDL keywords or bare boolean
|
|
67
|
+
# tokens, so a plain INSERT/UPDATE/DELETE/SELECT is returned untouched.
|
|
68
|
+
def translate_sql(sql)
|
|
68
69
|
sql = Tina4::SQLTranslator.auto_increment_syntax(sql, "mssql")
|
|
69
|
-
sql = Tina4::SQLTranslator.
|
|
70
|
+
sql = Tina4::SQLTranslator.boolean_to_int(sql)
|
|
71
|
+
Tina4::SQLTranslator.ddl_types(sql, "mssql")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def execute(sql, params = [])
|
|
75
|
+
sql = translate_sql(sql)
|
|
70
76
|
effective_sql = interpolate_params(sql, params)
|
|
71
77
|
|
|
72
78
|
# Capture the generated IDENTITY AT WRITE TIME — mirror of the Python
|
data/lib/tina4/seeder.rb
CHANGED
|
@@ -108,6 +108,30 @@ module Tina4
|
|
|
108
108
|
CURRENCIES = %w[USD EUR GBP JPY CAD AUD CHF ZAR INR CNY].freeze
|
|
109
109
|
CREDIT_CARD_PREFIXES = %w[4111 4242 5500 5105].freeze
|
|
110
110
|
|
|
111
|
+
# Product-name vocabulary (adjective + noun). Seeds a generic
|
|
112
|
+
# +name+/+full_name+ column on a product-ish table with "Wireless Keyboard"
|
|
113
|
+
# instead of a person name. Mirrors the Python master's word banks.
|
|
114
|
+
PRODUCT_ADJECTIVES = %w[
|
|
115
|
+
Wireless Organic Premium Classic Eco Smart Portable
|
|
116
|
+
Deluxe Compact Rustic Handcrafted Vintage Modern
|
|
117
|
+
Ergonomic Stainless Bamboo Recycled Artisan Professional
|
|
118
|
+
Ultra Insulated Lightweight Adjustable Foldable
|
|
119
|
+
].freeze
|
|
120
|
+
|
|
121
|
+
PRODUCT_NOUNS = [
|
|
122
|
+
"Keyboard", "Coffee Beans", "Backpack", "Water Bottle", "Desk Lamp",
|
|
123
|
+
"Headphones", "Notebook", "Sneakers", "Sunglasses", "Wallet", "Mug",
|
|
124
|
+
"Chair", "Blender", "Speaker", "Charger", "Umbrella", "Toothbrush",
|
|
125
|
+
"Jacket", "Watch", "Kettle", "Picture Frame", "Planter", "Cutlery Set",
|
|
126
|
+
"Yoga Mat", "Phone Case"
|
|
127
|
+
].freeze
|
|
128
|
+
|
|
129
|
+
# A table/model whose name contains any of these gets product names on its
|
|
130
|
+
# generic +name+/+full_name+ column instead of a person name.
|
|
131
|
+
PRODUCT_TABLE_HINTS = %w[
|
|
132
|
+
product item catalog inventory goods merchandise sku listing stock ware
|
|
133
|
+
].freeze
|
|
134
|
+
|
|
111
135
|
def initialize(seed: nil)
|
|
112
136
|
@rng = seed ? Random.new(seed) : Random.new
|
|
113
137
|
end
|
|
@@ -247,6 +271,23 @@ module Tina4
|
|
|
247
271
|
JOB_TITLES[@rng.rand(JOB_TITLES.length)]
|
|
248
272
|
end
|
|
249
273
|
|
|
274
|
+
# A plausible product name, e.g. "Wireless Keyboard" or "Organic Coffee
|
|
275
|
+
# Beans". Deterministic under a seed like every other generator (draws from
|
|
276
|
+
# the same @rng), so a seeded run reproduces it. Mirrors the Python master's
|
|
277
|
+
# FakeData.product().
|
|
278
|
+
def product
|
|
279
|
+
"#{PRODUCT_ADJECTIVES[@rng.rand(PRODUCT_ADJECTIVES.length)]} #{PRODUCT_NOUNS[@rng.rand(PRODUCT_NOUNS.length)]}"
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# True when the table/model name looks like a product catalogue, so a generic
|
|
283
|
+
# +name+/+full_name+ column seeds a product name, not a person name. With no
|
|
284
|
+
# table context (nil/"") this is false, so the person-name default is kept
|
|
285
|
+
# (back-compat). Mirrors the Python master's +_is_product_table+.
|
|
286
|
+
def self.product_table?(table)
|
|
287
|
+
down = table.to_s.downcase
|
|
288
|
+
PRODUCT_TABLE_HINTS.any? { |hint| down.include?(hint) }
|
|
289
|
+
end
|
|
290
|
+
|
|
250
291
|
def currency
|
|
251
292
|
CURRENCIES[@rng.rand(CURRENCIES.length)]
|
|
252
293
|
end
|
|
@@ -282,7 +323,13 @@ module Tina4
|
|
|
282
323
|
end
|
|
283
324
|
|
|
284
325
|
# Generate appropriate data based on field definition and column name.
|
|
285
|
-
|
|
326
|
+
#
|
|
327
|
+
# +table+ (optional) is the table/model name. When it names a product-ish
|
|
328
|
+
# catalogue (see FakeData.product_table?) a generic +name+/+full_name+/
|
|
329
|
+
# +fullname+ column yields a product name ("Wireless Keyboard") instead of a
|
|
330
|
+
# person name. With no table context the person-name default is kept
|
|
331
|
+
# (back-compat). first_name/last_name/user_name stay person either way.
|
|
332
|
+
def for_field(field_def, column_name = nil, table = nil)
|
|
286
333
|
col = (column_name || "").to_s.downcase
|
|
287
334
|
type = field_def[:type]
|
|
288
335
|
|
|
@@ -323,7 +370,7 @@ module Tina4
|
|
|
323
370
|
|
|
324
371
|
when :string, :text
|
|
325
372
|
max_len = field_def[:length] || 255
|
|
326
|
-
val = generate_string_for(col, max_len)
|
|
373
|
+
val = generate_string_for(col, max_len, table)
|
|
327
374
|
val.length > max_len ? val[0...max_len] : val
|
|
328
375
|
|
|
329
376
|
else
|
|
@@ -333,9 +380,15 @@ module Tina4
|
|
|
333
380
|
|
|
334
381
|
private
|
|
335
382
|
|
|
336
|
-
def generate_string_for(col, max_len)
|
|
383
|
+
def generate_string_for(col, max_len, table = nil)
|
|
337
384
|
return email[0...max_len] if col.include?("email")
|
|
338
|
-
|
|
385
|
+
if %w[name full_name fullname display_name].include?(col)
|
|
386
|
+
# GENERIC full-name column: a product-ish table gets a product name, any
|
|
387
|
+
# other table (or no table context) keeps the person name. first_name/
|
|
388
|
+
# last_name/user_name are handled by the branches below, so they stay
|
|
389
|
+
# person on a product table too.
|
|
390
|
+
return (self.class.product_table?(table) ? product : name)[0...max_len]
|
|
391
|
+
end
|
|
339
392
|
return first_name[0...max_len] if col.include?("first") && col.include?("name")
|
|
340
393
|
return last_name[0...max_len] if col.include?("last") && col.include?("name")
|
|
341
394
|
return last_name[0...max_len] if col =~ /surname|family_name/
|
|
@@ -523,7 +576,10 @@ module Tina4
|
|
|
523
576
|
elsif fk_pools[name] && !fk_pools[name].empty?
|
|
524
577
|
attrs[name] = fake.choice(fk_pools[name])
|
|
525
578
|
else
|
|
526
|
-
|
|
579
|
+
# Thread the MODEL name (orm_class.name) so a generic name column on
|
|
580
|
+
# a product-ish model seeds a product name (parity with the Python
|
|
581
|
+
# master, which passes orm_class.__name__).
|
|
582
|
+
generated = fake.for_field(field_def, name, orm_class.name)
|
|
527
583
|
attrs[name] = generated unless generated.nil?
|
|
528
584
|
end
|
|
529
585
|
end
|
|
@@ -614,7 +670,10 @@ module Tina4
|
|
|
614
670
|
row[col_name] = type_str.arity.zero? ? type_str.call : type_str.call(fake)
|
|
615
671
|
else
|
|
616
672
|
field_def = { type: type_str.to_sym }
|
|
617
|
-
|
|
673
|
+
# Thread the TABLE name so a generic name column on a product-ish
|
|
674
|
+
# table (incl. the MCP seed_table dev tool, which reaches here via
|
|
675
|
+
# db.columns) seeds a product name instead of a person name.
|
|
676
|
+
row[col_name] = fake.for_field(field_def, col_name, table_name)
|
|
618
677
|
end
|
|
619
678
|
end
|
|
620
679
|
|
data/lib/tina4/version.rb
CHANGED