brick 1.0.54 → 1.0.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/brick/extensions.rb +9 -13
- data/lib/brick/version_number.rb +1 -1
- data/lib/generators/brick/migrations_generator.rb +106 -38
- 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: 430a2dfa5ef0caee9b99bc341ccd42a9d29e8f1d54071284aa2469e1baa0c659
|
|
4
|
+
data.tar.gz: b36e18de169bd9032e6c383548ec30cce06eeb97a35e8c3e4f4da935aff8f603
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c51491575b9ee56c3789619bfc74a2d9c0525750687224e94e120cbae42fad8db1abda9d82978115d9266c55fa0c6f914ce273a3613915657d8a0cf4e7fe6aeb
|
|
7
|
+
data.tar.gz: a0646cfdc9a2c844fd1149968d0175346c48835c6245d7fe92d0126d60708cf76514704e29dc3f506d2e06e546c8c995bf7103d6ef42be481bb931b4d2bfa73f
|
data/lib/brick/extensions.rb
CHANGED
|
@@ -1316,16 +1316,21 @@ module ActiveRecord::ConnectionHandling
|
|
|
1316
1316
|
# puts ActiveRecord::Base.execute_sql("SELECT current_setting('SEARCH_PATH')").to_a.inspect
|
|
1317
1317
|
|
|
1318
1318
|
is_postgres = nil
|
|
1319
|
-
schema_sql = 'SELECT NULL AS table_schema;'
|
|
1320
1319
|
case ActiveRecord::Base.connection.adapter_name
|
|
1321
1320
|
when 'PostgreSQL'
|
|
1322
1321
|
is_postgres = true
|
|
1322
|
+
db_schemas = ActiveRecord::Base.execute_sql('SELECT DISTINCT table_schema FROM INFORMATION_SCHEMA.tables;')
|
|
1323
|
+
::Brick.db_schemas = db_schemas.each_with_object({}) do |row, s|
|
|
1324
|
+
row = row.is_a?(String) ? row : row['table_schema']
|
|
1325
|
+
# Remove any system schemas
|
|
1326
|
+
s[row] = nil unless ['information_schema', 'pg_catalog'].include?(row)
|
|
1327
|
+
end
|
|
1323
1328
|
if (is_multitenant = (multitenancy = ::Brick.config.schema_behavior[:multitenant]) &&
|
|
1324
|
-
(sta = multitenancy[:schema_to_analyse]) != 'public')
|
|
1329
|
+
(sta = multitenancy[:schema_to_analyse]) != 'public') &&
|
|
1330
|
+
::Brick.db_schemas.include?(sta)
|
|
1325
1331
|
::Brick.default_schema = schema = sta
|
|
1326
1332
|
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", schema)
|
|
1327
1333
|
end
|
|
1328
|
-
schema_sql = 'SELECT DISTINCT table_schema FROM INFORMATION_SCHEMA.tables;'
|
|
1329
1334
|
when 'Mysql2'
|
|
1330
1335
|
::Brick.default_schema = schema = ActiveRecord::Base.connection.current_database
|
|
1331
1336
|
when 'SQLite'
|
|
@@ -1342,16 +1347,7 @@ module ActiveRecord::ConnectionHandling
|
|
|
1342
1347
|
puts "Unfamiliar with connection adapter #{ActiveRecord::Base.connection.adapter_name}"
|
|
1343
1348
|
end
|
|
1344
1349
|
|
|
1345
|
-
|
|
1346
|
-
db_schemas = db_schemas.to_a
|
|
1347
|
-
end
|
|
1348
|
-
unless db_schemas.empty?
|
|
1349
|
-
::Brick.db_schemas = db_schemas.each_with_object({}) do |row, s|
|
|
1350
|
-
row = row.is_a?(String) ? row : row['table_schema']
|
|
1351
|
-
# Remove any system schemas
|
|
1352
|
-
s[row] = nil unless ['information_schema', 'pg_catalog'].include?(row)
|
|
1353
|
-
end
|
|
1354
|
-
end
|
|
1350
|
+
::Brick.db_schemas ||= []
|
|
1355
1351
|
|
|
1356
1352
|
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
|
1357
1353
|
if (possible_schema = ::Brick.config.schema_behavior&.[](:multitenant)&.[](:schema_to_analyse))
|
data/lib/brick/version_number.rb
CHANGED
|
@@ -10,11 +10,17 @@ module Brick
|
|
|
10
10
|
include FancyGets
|
|
11
11
|
# include ::Rails::Generators::Migration
|
|
12
12
|
|
|
13
|
-
# SQL types that are the same as their migration data type name: text, integer, bigint,
|
|
14
|
-
SQL_TYPES = { 'character varying' =>'string',
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
'
|
|
13
|
+
# SQL types that are the same as their migration data type name: text, integer, bigint, date, boolean, decimal, float
|
|
14
|
+
SQL_TYPES = { 'character varying' => 'string',
|
|
15
|
+
'character' => 'string', # %%% Need to put in "limit: 1"
|
|
16
|
+
'xml' => 'text',
|
|
17
|
+
'bytea' => 'binary',
|
|
18
|
+
'timestamp without time zone' => 'timestamp',
|
|
19
|
+
'timestamp with time zone' => 'timestamp',
|
|
20
|
+
'time without time zone' => 'time',
|
|
21
|
+
'time with time zone' => 'time',
|
|
22
|
+
'double precision' => 'float', # might work with 'double'
|
|
23
|
+
'smallint' => 'integer' } # %%% Need to put in "limit: 2"
|
|
18
24
|
# (Still need to find what "inet" and "json" data types map to.)
|
|
19
25
|
|
|
20
26
|
# # source_root File.expand_path('templates', __dir__)
|
|
@@ -38,24 +44,22 @@ module Brick
|
|
|
38
44
|
return
|
|
39
45
|
end
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
end
|
|
46
|
-
default_mig_path = (mig_path = ActiveRecord::Migrator.migrations_paths.first || "#{File.expand_path(__dir__)}/db/migrate")
|
|
47
|
+
key_type = (ActiveRecord.version < ::Gem::Version.new('5.1') ? 'integer' : 'bigint')
|
|
48
|
+
is_4x_rails = ActiveRecord.version < ::Gem::Version.new('5.0')
|
|
49
|
+
ar_version = "[#{ActiveRecord.version.segments[0..1].join('.')}]" unless is_4x_rails
|
|
50
|
+
default_mig_path = (mig_path = ActiveRecord::Migrator.migrations_paths.first || "#{::Rails.root}/db/migrate")
|
|
47
51
|
if Dir.exist?(mig_path)
|
|
48
52
|
if Dir["#{mig_path}/**/*.rb"].present?
|
|
49
53
|
puts "WARNING: migrations folder #{mig_path} appears to already have ruby files present."
|
|
50
|
-
mig_path2 = "#{
|
|
54
|
+
mig_path2 = "#{::Rails.root}/tmp/brick_migrations"
|
|
51
55
|
if Dir.exist?(mig_path2)
|
|
52
56
|
if Dir["#{mig_path2}/**/*.rb"].present?
|
|
53
57
|
puts "As well, temporary folder #{mig_path2} also has ruby files present."
|
|
54
58
|
puts "Choose a destination -- all existing .rb files will be removed:"
|
|
55
|
-
mig_path2 = gets_list(list: ['Cancel operation!', "
|
|
59
|
+
mig_path2 = gets_list(list: ['Cancel operation!', "Append migration files into #{mig_path} anyway", mig_path, mig_path2])
|
|
56
60
|
return if mig_path2.start_with?('Cancel')
|
|
57
61
|
|
|
58
|
-
if mig_path2.start_with?('
|
|
62
|
+
if mig_path2.start_with?('Append migration files into ')
|
|
59
63
|
mig_path2 = mig_path
|
|
60
64
|
else
|
|
61
65
|
Dir["#{mig_path2}/**/*.rb"].each { |rb| File.delete(rb) }
|
|
@@ -78,7 +82,7 @@ module Brick
|
|
|
78
82
|
|
|
79
83
|
# Generate a list of tables that can be chosen
|
|
80
84
|
chosen = gets_list(list: tables, chosen: tables.dup)
|
|
81
|
-
#
|
|
85
|
+
# Start the timestamps back the same number of minutes from now as expected number of migrations to create
|
|
82
86
|
current_mig_time = Time.now - chosen.length.minutes
|
|
83
87
|
done = []
|
|
84
88
|
fks = {}
|
|
@@ -87,48 +91,110 @@ module Brick
|
|
|
87
91
|
# Continue layer by layer, creating migrations for tables that reference ones already done, until
|
|
88
92
|
# no more migrations can be created. (At that point hopefully all tables are accounted for.)
|
|
89
93
|
while (fringe = chosen.reject do |tbl|
|
|
90
|
-
snags = ::Brick.relations
|
|
94
|
+
snags = ::Brick.relations.fetch(tbl, nil)&.fetch(:fks, nil)&.select do |_k, v|
|
|
91
95
|
v[:is_bt] && !v[:polymorphic] &&
|
|
92
96
|
tbl != v[:inverse_table] && # Ignore self-referencing associations (stuff like "parent_id")
|
|
93
97
|
!done.include?(v[:inverse_table])
|
|
94
98
|
end
|
|
95
|
-
stuck[tbl] = snags if snags
|
|
99
|
+
stuck[tbl] = snags if snags&.present?
|
|
96
100
|
end).present?
|
|
97
101
|
fringe.each do |tbl|
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
next unless (relation = ::Brick.relations.fetch(tbl, nil))&.fetch(:cols, nil)&.present?
|
|
103
|
+
|
|
104
|
+
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [ActiveRecord::Base.primary_key].flatten)
|
|
105
|
+
# In case things aren't as standard
|
|
106
|
+
if pkey_cols.empty?
|
|
107
|
+
pkey_cols = if rpk.empty? && relation[:cols][arpk.first]&.first == key_type
|
|
108
|
+
arpk
|
|
109
|
+
elsif rpk.first
|
|
110
|
+
rpk
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
schema = if (tbl_parts = tbl.split('.')).length > 1
|
|
114
|
+
if tbl_parts.first == 'public'
|
|
115
|
+
tbl_parts.shift
|
|
116
|
+
nil
|
|
117
|
+
else
|
|
118
|
+
tbl_parts.first
|
|
119
|
+
end
|
|
120
|
+
end
|
|
100
121
|
# %%% For the moment we're skipping polymorphics
|
|
101
|
-
fkey_cols =
|
|
102
|
-
mig = +"class Create#{
|
|
103
|
-
#
|
|
104
|
-
# also
|
|
105
|
-
|
|
122
|
+
fkey_cols = relation[:fks].values.select { |assoc| assoc[:is_bt] && !assoc[:polymorphic] }
|
|
123
|
+
mig = +"class Create#{(full_table_name = tbl_parts.join('_')).camelize} < ActiveRecord::Migration#{ar_version}\n"
|
|
124
|
+
# Support missing primary key (by adding: ,id: false)
|
|
125
|
+
# also integer / uuid / other non-standard data types for primary key
|
|
126
|
+
id_option = unless (pkey_col_first = relation[:cols][pkey_cols&.first]&.first) == key_type
|
|
127
|
+
unless pkey_cols&.present?
|
|
128
|
+
', id: false'
|
|
129
|
+
else
|
|
130
|
+
case pkey_col_first
|
|
131
|
+
when 'integer'
|
|
132
|
+
', id: :serial'
|
|
133
|
+
when 'bigint'
|
|
134
|
+
', id: :bigserial'
|
|
135
|
+
else
|
|
136
|
+
", id: :#{SQL_TYPES[pkey_col_first] || pkey_col_first}" # Something like: id: :integer, primary_key: :businessentityid
|
|
137
|
+
end + (pkey_cols.first ? ", primary_key: :#{pkey_cols.first}" : '')
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
# Refer to this table name as a symbol or dotted string as appropriate
|
|
141
|
+
tbl = tbl_parts.length == 1 ? ":#{tbl_parts.first}" : "'#{tbl}'"
|
|
142
|
+
mig << " def change\n return unless reverting? || !table_exists?(#{tbl})\n\n"
|
|
143
|
+
mig << " create_schema :#{schema} unless schema_exists?(:#{schema})\n" if schema
|
|
144
|
+
mig << " create_table #{tbl}#{id_option} do |t|\n"
|
|
106
145
|
possible_ts = [] # Track possible generic timestamps
|
|
107
|
-
|
|
108
|
-
|
|
146
|
+
add_fks = [] # Track foreign keys to add after table creation
|
|
147
|
+
relation[:cols].each do |col, col_type|
|
|
148
|
+
next if !id_option&.end_with?('id: false') && pkey_cols.include?(col)
|
|
109
149
|
|
|
110
150
|
# See if there are generic timestamps
|
|
111
|
-
if (sql_type = SQL_TYPES[col_type.first]) == 'timestamp' &&
|
|
112
|
-
|
|
151
|
+
if (sql_type = SQL_TYPES[col_type.first]) == 'timestamp' &&
|
|
152
|
+
['created_at','updated_at'].include?(col)
|
|
153
|
+
possible_ts << [col, !col_type[3]]
|
|
113
154
|
next
|
|
114
155
|
end
|
|
115
156
|
|
|
116
157
|
sql_type ||= col_type.first
|
|
158
|
+
suffix = col_type[3] ? +', null: false' : +''
|
|
117
159
|
# Determine if this column is used as part of a foreign key
|
|
118
160
|
if fk = fkey_cols.find { |assoc| col == assoc[:fk] }
|
|
119
|
-
|
|
161
|
+
to_table = fk[:inverse_table].split('.')
|
|
162
|
+
to_table = to_table.length == 1 ? ":#{to_table.first}" : "'#{fk[:inverse_table]}'"
|
|
163
|
+
if fk[:fk] != "#{fk[:assoc_name].singularize}_id" # Need to do our own foreign_key tricks, not use references?
|
|
164
|
+
column = fk[:fk]
|
|
165
|
+
mig << " t.#{sql_type} :#{column}#{suffix}\n"
|
|
166
|
+
add_fks << [to_table, column, ::Brick.relations[fk[:inverse_table]]]
|
|
167
|
+
else
|
|
168
|
+
suffix << ", type: :#{sql_type}" unless sql_type == key_type
|
|
169
|
+
mig << " t.references :#{fk[:assoc_name]}#{suffix}, foreign_key: { to_table: #{to_table} }\n"
|
|
170
|
+
end
|
|
120
171
|
else
|
|
121
|
-
mig << emit_column(sql_type, col)
|
|
172
|
+
mig << emit_column(sql_type, col, suffix)
|
|
122
173
|
end
|
|
123
174
|
end
|
|
124
|
-
if possible_ts.length == 2 # Both created_at and updated_at
|
|
175
|
+
if possible_ts.length == 2 && # Both created_at and updated_at
|
|
176
|
+
# Rails 5 and later timestamps default to NOT NULL
|
|
177
|
+
(possible_ts.first.last == is_4x_rails && possible_ts.last.last == is_4x_rails)
|
|
125
178
|
mig << "\n t.timestamps\n"
|
|
126
|
-
else # Just one or the other
|
|
127
|
-
possible_ts.each { |ts| emit_column('timestamp', ts) }
|
|
179
|
+
else # Just one or the other, or a nullability mismatch
|
|
180
|
+
possible_ts.each { |ts| emit_column('timestamp', ts.first, nil) }
|
|
128
181
|
end
|
|
129
|
-
mig << " end\n
|
|
182
|
+
mig << " end\n"
|
|
183
|
+
add_fks.each do |add_fk|
|
|
184
|
+
is_commented = false
|
|
185
|
+
# add_fk[2] holds the inverse relation
|
|
186
|
+
unless (pk = add_fk[2][:pkey].values.flatten&.first)
|
|
187
|
+
is_commented = true
|
|
188
|
+
mig << " # (Unable to create relationship because primary key is missing on table #{add_fk[0]})\n"
|
|
189
|
+
# No official PK, but if coincidentally there's a column of the same name, take a chance on it
|
|
190
|
+
pk = (add_fk[2][:cols].key?(add_fk[1]) && add_fk[1]) || '???'
|
|
191
|
+
end
|
|
192
|
+
# to_table column
|
|
193
|
+
mig << " #{'# ' if is_commented}add_foreign_key #{tbl}, #{add_fk[0]}, column: :#{add_fk[1]}, primary_key: :#{pk}\n"
|
|
194
|
+
end
|
|
195
|
+
mig << " end\nend\n"
|
|
130
196
|
current_mig_time += 1.minute
|
|
131
|
-
File.open("#{mig_path}/#{current_mig_time.strftime('%Y%m%d%H%M00')}_create_#{
|
|
197
|
+
File.open("#{mig_path}/#{current_mig_time.strftime('%Y%m%d%H%M00')}_create_#{full_table_name}.rb", "w") { |f| f.write mig }
|
|
132
198
|
end
|
|
133
199
|
done.concat(fringe)
|
|
134
200
|
chosen -= done
|
|
@@ -140,7 +206,9 @@ module Brick
|
|
|
140
206
|
snag.last[:assoc_name]
|
|
141
207
|
end.join(', ')}"
|
|
142
208
|
end
|
|
143
|
-
|
|
209
|
+
if mig_path.start_with?(cur_path = ::Rails.root.to_s)
|
|
210
|
+
pretty_mig_path = mig_path[cur_path.length..-1]
|
|
211
|
+
end
|
|
144
212
|
puts "*** Created #{done.length} migration files under #{pretty_mig_path || mig_path} ***"
|
|
145
213
|
if (stuck_sorted = stuck_counts.to_a.sort { |a, b| b.last <=> a.last }).length.positive?
|
|
146
214
|
puts "-----------------------------------------"
|
|
@@ -153,8 +221,8 @@ module Brick
|
|
|
153
221
|
|
|
154
222
|
private
|
|
155
223
|
|
|
156
|
-
def emit_column(type, name)
|
|
157
|
-
" t.#{type.start_with?('numeric') ? 'decimal' : type} :#{name}\n"
|
|
224
|
+
def emit_column(type, name, suffix)
|
|
225
|
+
" t.#{type.start_with?('numeric') ? 'decimal' : type} :#{name}#{suffix}\n"
|
|
158
226
|
end
|
|
159
227
|
end
|
|
160
228
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brick
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.55
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lorin Thwaits
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-08-
|
|
11
|
+
date: 2022-08-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|