db_schema-reader-postgres 0.1.1 → 0.2.rc1
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/.travis.yml +4 -4
- data/Gemfile +2 -0
- data/db_schema-reader-postgres.gemspec +1 -1
- data/lib/db_schema/reader/postgres.rb +202 -6
- data/lib/db_schema/reader/postgres/table.rb +108 -198
- data/lib/db_schema/reader/postgres/version.rb +1 -1
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b2b3ebe11fc219d52a9576207a384fa6dd8f9b6178a5a65efaadbb215c3dcd9
|
4
|
+
data.tar.gz: 0fbc9926bcf4429875278c1d9b9157cf91618f6dad67c245c109fd85dbfc04e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f55b980f9ceb11448e1699da20f071dcc75cbd79c3dfee4869081f2fb1450b04d0027be2df92310082a5c54144c5ce8df27efa21cc1d9d19365a0127280512e
|
7
|
+
data.tar.gz: 809c304408c6f03014db7ad5169f36f6616d3765d6e31a96f6ee6e566d3e3c963788a6df796eac373e59851cc42c0b69ae21a335ceb2f2a7399adde32d1ac1db
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_runtime_dependency 'sequel'
|
22
22
|
spec.add_runtime_dependency 'pg'
|
23
|
-
spec.add_runtime_dependency 'db_schema-definitions', '
|
23
|
+
spec.add_runtime_dependency 'db_schema-definitions', '= 0.2.rc1'
|
24
24
|
|
25
25
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
26
26
|
spec.add_development_dependency 'rake', '~> 10.0'
|
@@ -5,6 +5,84 @@ require_relative 'postgres/version'
|
|
5
5
|
module DbSchema
|
6
6
|
module Reader
|
7
7
|
class Postgres
|
8
|
+
COLUMNS_QUERY = <<-SQL.freeze
|
9
|
+
SELECT c.table_name,
|
10
|
+
c.column_name AS name,
|
11
|
+
c.ordinal_position AS pos,
|
12
|
+
c.column_default AS default,
|
13
|
+
c.is_nullable AS null,
|
14
|
+
c.data_type AS type,
|
15
|
+
c.is_identity,
|
16
|
+
c.udt_name AS custom_type_name,
|
17
|
+
c.character_maximum_length AS char_length,
|
18
|
+
c.numeric_precision AS num_precision,
|
19
|
+
c.numeric_scale AS num_scale,
|
20
|
+
c.datetime_precision AS dt_precision,
|
21
|
+
c.interval_type,
|
22
|
+
e.data_type AS element_type,
|
23
|
+
e.udt_name AS element_custom_type_name
|
24
|
+
FROM information_schema.columns AS c
|
25
|
+
LEFT JOIN information_schema.element_types AS e
|
26
|
+
ON e.object_catalog = c.table_catalog
|
27
|
+
AND e.object_schema = c.table_schema
|
28
|
+
AND e.object_name = c.table_name
|
29
|
+
AND e.object_type = 'TABLE'
|
30
|
+
AND e.collection_type_identifier = c.dtd_identifier
|
31
|
+
WHERE c.table_schema = 'public'
|
32
|
+
SQL
|
33
|
+
|
34
|
+
INDEXES_QUERY = <<-SQL.freeze
|
35
|
+
SELECT table_rel.relname AS table_name,
|
36
|
+
pg_class.relname AS name,
|
37
|
+
indkey AS column_positions,
|
38
|
+
indisprimary AS primary,
|
39
|
+
indisunique AS unique,
|
40
|
+
indoption AS index_options,
|
41
|
+
pg_get_expr(indpred, indrelid, true) AS condition,
|
42
|
+
amname AS index_type,
|
43
|
+
indexrelid AS index_oid
|
44
|
+
FROM pg_class, pg_index
|
45
|
+
LEFT JOIN pg_opclass
|
46
|
+
ON pg_opclass.oid = ANY(pg_index.indclass::int[])
|
47
|
+
LEFT JOIN pg_am
|
48
|
+
ON pg_am.oid = pg_opclass.opcmethod
|
49
|
+
JOIN pg_class AS table_rel
|
50
|
+
ON table_rel.oid = pg_index.indrelid
|
51
|
+
JOIN pg_namespace
|
52
|
+
ON pg_namespace.oid = table_rel.relnamespace
|
53
|
+
WHERE pg_class.oid = pg_index.indexrelid
|
54
|
+
AND pg_namespace.nspname = 'public'
|
55
|
+
GROUP BY table_name, name, column_positions, indisprimary, indisunique, index_options, condition, index_type, index_oid
|
56
|
+
SQL
|
57
|
+
|
58
|
+
EXPRESSION_INDEXES_QUERY = <<-SQL.freeze
|
59
|
+
WITH index_ids AS (SELECT unnest(?) AS index_id),
|
60
|
+
elements AS (SELECT unnest(?) AS element)
|
61
|
+
SELECT index_id,
|
62
|
+
array_agg(pg_get_indexdef(index_id, element, 't')) AS definitions
|
63
|
+
FROM index_ids, elements
|
64
|
+
GROUP BY index_id;
|
65
|
+
SQL
|
66
|
+
|
67
|
+
CONSTRAINTS_QUERY = <<-SQL.freeze
|
68
|
+
SELECT owner_table.relname AS table_name,
|
69
|
+
constr.conname AS name,
|
70
|
+
pg_get_expr(conbin, conrelid, true) AS condition,
|
71
|
+
referenced_table.relname AS referenced,
|
72
|
+
conkey,
|
73
|
+
confkey,
|
74
|
+
confupdtype AS on_update,
|
75
|
+
confdeltype AS on_delete,
|
76
|
+
condeferrable AS deferrable,
|
77
|
+
constr.contype AS type
|
78
|
+
FROM pg_constraint AS constr
|
79
|
+
JOIN pg_class AS owner_table
|
80
|
+
ON owner_table.oid = constr.conrelid
|
81
|
+
LEFT JOIN pg_class AS referenced_table
|
82
|
+
ON referenced_table.oid = constr.confrelid
|
83
|
+
WHERE contype IN ('c', 'f');
|
84
|
+
SQL
|
85
|
+
|
8
86
|
ENUMS_QUERY = <<-SQL.freeze
|
9
87
|
SELECT t.typname AS name,
|
10
88
|
array_agg(e.enumlabel ORDER BY e.enumsortorder) AS values
|
@@ -35,13 +113,17 @@ SELECT extname
|
|
35
113
|
end
|
36
114
|
|
37
115
|
def read_tables
|
38
|
-
|
39
|
-
read_table(table_name)
|
40
|
-
end
|
41
|
-
end
|
116
|
+
checks_data, foreign_keys_data = constraints_data
|
42
117
|
|
43
|
-
|
44
|
-
|
118
|
+
columns_data.keys.map do |table_name|
|
119
|
+
Table.new(
|
120
|
+
table_name.to_sym,
|
121
|
+
columns_data[table_name],
|
122
|
+
indexes_data[table_name],
|
123
|
+
checks_data[table_name],
|
124
|
+
foreign_keys_data[table_name]
|
125
|
+
).definition
|
126
|
+
end
|
45
127
|
end
|
46
128
|
|
47
129
|
def read_enums
|
@@ -55,6 +137,120 @@ SELECT extname
|
|
55
137
|
Definitions::Extension.new(extension_data[:extname].to_sym)
|
56
138
|
end
|
57
139
|
end
|
140
|
+
|
141
|
+
private
|
142
|
+
def columns_data
|
143
|
+
@columns_data ||= connection[COLUMNS_QUERY].to_a.group_by do |column|
|
144
|
+
column[:table_name]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def indexes_data
|
149
|
+
@indexes_data ||= begin
|
150
|
+
raw_data = connection[INDEXES_QUERY].map do |index_data|
|
151
|
+
index_data.merge(
|
152
|
+
column_positions: index_data[:column_positions].split(' ').map(&:to_i),
|
153
|
+
index_options: index_data[:index_options].split(' ').map(&:to_i)
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
157
|
+
expressions_data = index_expressions_data(raw_data)
|
158
|
+
|
159
|
+
raw_data.map do |index_data|
|
160
|
+
columns = index_data[:column_positions].map do |position|
|
161
|
+
if position.zero?
|
162
|
+
expressions_data.fetch(index_data[:index_oid]).shift
|
163
|
+
else
|
164
|
+
get_field_name(index_data[:table_name], position)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
index_data.delete(:index_oid)
|
169
|
+
index_data.delete(:column_positions)
|
170
|
+
index_data.merge(columns: columns)
|
171
|
+
end.group_by { |index| index[:table_name] }.tap { |h| h.default = [] }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def index_expressions_data(indexes_data)
|
176
|
+
all_positions, max_position = {}, 0
|
177
|
+
|
178
|
+
indexes_data.each do |index_data|
|
179
|
+
positions = index_data[:column_positions]
|
180
|
+
expression_positions = positions.each_index.select do |i|
|
181
|
+
positions[i].zero?
|
182
|
+
end
|
183
|
+
|
184
|
+
if expression_positions.any?
|
185
|
+
all_positions[index_data[:index_oid]] = expression_positions
|
186
|
+
max_position = [max_position, expression_positions.max].max
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
if all_positions.any?
|
191
|
+
connection[
|
192
|
+
EXPRESSION_INDEXES_QUERY,
|
193
|
+
Sequel.pg_array(all_positions.keys),
|
194
|
+
Sequel.pg_array((1..max_position.succ).to_a)
|
195
|
+
].each_with_object({}) do |index_data, indexes_data|
|
196
|
+
index_id = index_data[:index_id]
|
197
|
+
expressions = all_positions[index_id].map { |pos| index_data[:definitions][pos] }
|
198
|
+
|
199
|
+
indexes_data[index_id] = expressions
|
200
|
+
end
|
201
|
+
else
|
202
|
+
{}
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def constraints_data
|
207
|
+
checks = Hash.new { |h, k| h[k] = [] }
|
208
|
+
foreign_keys = Hash.new { |h, k| h[k] = [] }
|
209
|
+
|
210
|
+
connection[CONSTRAINTS_QUERY].each do |constraint|
|
211
|
+
case constraint[:type]
|
212
|
+
when 'c'
|
213
|
+
checks[constraint[:table_name]] << {
|
214
|
+
name: constraint[:name],
|
215
|
+
condition: constraint[:condition]
|
216
|
+
}
|
217
|
+
when 'f'
|
218
|
+
fields = constraint[:conkey].map do |position|
|
219
|
+
get_field_name(constraint[:table_name], position)
|
220
|
+
end
|
221
|
+
|
222
|
+
keys = constraint[:confkey].map do |position|
|
223
|
+
get_field_name(constraint[:referenced], position)
|
224
|
+
end
|
225
|
+
|
226
|
+
pkey_columns = indexes_data.fetch(constraint[:referenced]).find do |index|
|
227
|
+
index[:primary]
|
228
|
+
end.fetch(:columns)
|
229
|
+
|
230
|
+
keys = [] if keys == pkey_columns # this foreign key references a primary key
|
231
|
+
|
232
|
+
foreign_keys[constraint[:table_name]] << {
|
233
|
+
name: constraint[:name],
|
234
|
+
referenced: constraint[:referenced],
|
235
|
+
fields: fields,
|
236
|
+
keys: keys,
|
237
|
+
on_update: constraint[:on_update],
|
238
|
+
on_delete: constraint[:on_delete],
|
239
|
+
deferrable: constraint[:deferrable]
|
240
|
+
}
|
241
|
+
else
|
242
|
+
raise "Unknown constraint type #{constraint[:type].inspect}"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
[checks, foreign_keys]
|
247
|
+
end
|
248
|
+
|
249
|
+
def get_field_name(table, position)
|
250
|
+
columns_data.fetch(table).find do |column|
|
251
|
+
column[:pos] == position
|
252
|
+
end.fetch(:name).to_sym
|
253
|
+
end
|
58
254
|
end
|
59
255
|
end
|
60
256
|
end
|
@@ -2,6 +2,12 @@ module DbSchema
|
|
2
2
|
module Reader
|
3
3
|
class Postgres
|
4
4
|
class Table
|
5
|
+
SERIAL_TYPES = {
|
6
|
+
smallint: :smallserial,
|
7
|
+
integer: :serial,
|
8
|
+
bigint: :bigserial
|
9
|
+
}.freeze
|
10
|
+
|
5
11
|
DEFAULT_VALUE = /\A(
|
6
12
|
('(?<date>\d{4}-\d{2}-\d{2})'::date)
|
7
13
|
|
|
@@ -16,102 +22,25 @@ module DbSchema
|
|
16
22
|
(?<boolean>true|false)
|
17
23
|
)/x
|
18
24
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
c
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
ON e.object_catalog = c.table_catalog
|
36
|
-
AND e.object_schema = c.table_schema
|
37
|
-
AND e.object_name = c.table_name
|
38
|
-
AND e.object_type = 'TABLE'
|
39
|
-
AND e.collection_type_identifier = c.dtd_identifier
|
40
|
-
WHERE c.table_schema = 'public'
|
41
|
-
AND c.table_name = ?
|
42
|
-
SQL
|
43
|
-
|
44
|
-
CONSTRAINTS_QUERY = <<-SQL.freeze
|
45
|
-
SELECT conname AS name,
|
46
|
-
pg_get_expr(conbin, conrelid, true) AS condition
|
47
|
-
FROM pg_constraint, pg_class
|
48
|
-
WHERE conrelid = pg_class.oid
|
49
|
-
AND relname = ?
|
50
|
-
AND contype = 'c'
|
51
|
-
SQL
|
52
|
-
|
53
|
-
INDEXES_QUERY = <<-SQL.freeze
|
54
|
-
SELECT relname AS name,
|
55
|
-
indkey AS column_positions,
|
56
|
-
indisunique AS unique,
|
57
|
-
indoption AS index_options,
|
58
|
-
pg_get_expr(indpred, indrelid, true) AS condition,
|
59
|
-
amname AS index_type,
|
60
|
-
indexrelid AS index_oid
|
61
|
-
FROM pg_class, pg_index
|
62
|
-
LEFT JOIN pg_opclass
|
63
|
-
ON pg_opclass.oid = ANY(pg_index.indclass::int[])
|
64
|
-
LEFT JOIN pg_am
|
65
|
-
ON pg_am.oid = pg_opclass.opcmethod
|
66
|
-
WHERE pg_class.oid = pg_index.indexrelid
|
67
|
-
AND pg_class.oid IN (
|
68
|
-
SELECT indexrelid
|
69
|
-
FROM pg_index, pg_class
|
70
|
-
WHERE pg_class.relname = ?
|
71
|
-
AND pg_class.oid = pg_index.indrelid
|
72
|
-
AND indisprimary != 't'
|
73
|
-
)
|
74
|
-
GROUP BY name, column_positions, indisunique, index_options, condition, index_type, index_oid
|
75
|
-
SQL
|
76
|
-
|
77
|
-
EXPRESSION_INDEXES_QUERY = <<-SQL.freeze
|
78
|
-
WITH index_ids AS (SELECT unnest(?) AS index_id),
|
79
|
-
elements AS (SELECT unnest(?) AS element)
|
80
|
-
SELECT index_id,
|
81
|
-
array_agg(pg_get_indexdef(index_id, element, 't')) AS definitions
|
82
|
-
FROM index_ids, elements
|
83
|
-
GROUP BY index_id;
|
84
|
-
SQL
|
85
|
-
|
86
|
-
attr_reader :connection, :table_name
|
87
|
-
|
88
|
-
def initialize(connection, table_name)
|
89
|
-
@connection = connection
|
90
|
-
@table_name = table_name
|
25
|
+
FKEY_ACTIONS = {
|
26
|
+
a: :no_action,
|
27
|
+
r: :restrict,
|
28
|
+
c: :cascade,
|
29
|
+
n: :set_null,
|
30
|
+
d: :set_default
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
attr_reader :table_name, :fields_data, :indexes_data, :checks_data, :fkeys_data
|
34
|
+
|
35
|
+
def initialize(table_name, fields_data, indexes_data, checks_data, fkeys_data)
|
36
|
+
@table_name = table_name
|
37
|
+
@fields_data = fields_data
|
38
|
+
@indexes_data = indexes_data
|
39
|
+
@checks_data = checks_data
|
40
|
+
@fkeys_data = fkeys_data
|
91
41
|
end
|
92
42
|
|
93
|
-
def
|
94
|
-
primary_key_name = connection.primary_key(table_name)
|
95
|
-
|
96
|
-
fields = columns_data.map do |column_data|
|
97
|
-
build_field(column_data, primary_key: column_data[:name] == primary_key_name)
|
98
|
-
end
|
99
|
-
|
100
|
-
indexes = indexes_data.map do |index_data|
|
101
|
-
Definitions::Index.new(index_data)
|
102
|
-
end.sort_by(&:name)
|
103
|
-
|
104
|
-
foreign_keys = connection.foreign_key_list(table_name).map do |foreign_key_data|
|
105
|
-
build_foreign_key(foreign_key_data)
|
106
|
-
end
|
107
|
-
|
108
|
-
checks = connection[CONSTRAINTS_QUERY, table_name.to_s].map do |check_data|
|
109
|
-
Definitions::CheckConstraint.new(
|
110
|
-
name: check_data[:name].to_sym,
|
111
|
-
condition: check_data[:condition]
|
112
|
-
)
|
113
|
-
end
|
114
|
-
|
43
|
+
def definition
|
115
44
|
Definitions::Table.new(
|
116
45
|
table_name,
|
117
46
|
fields: fields,
|
@@ -121,107 +50,71 @@ GROUP BY index_id;
|
|
121
50
|
)
|
122
51
|
end
|
123
52
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
128
|
-
|
129
|
-
def indexes_data
|
130
|
-
column_names = columns_data.reduce({}) do |names, column|
|
131
|
-
names.merge(column[:pos] => column[:name].to_sym)
|
132
|
-
end
|
133
|
-
|
134
|
-
indexes_data = connection[INDEXES_QUERY, table_name.to_s].to_a
|
135
|
-
expressions_data = index_expressions_data(indexes_data)
|
136
|
-
|
137
|
-
indexes_data.map do |index|
|
138
|
-
positions = index[:column_positions].split(' ').map(&:to_i)
|
139
|
-
options = index[:index_options].split(' ').map(&:to_i)
|
140
|
-
|
141
|
-
columns = positions.zip(options).map do |column_position, column_order_options|
|
142
|
-
options = case column_order_options
|
143
|
-
when 0
|
144
|
-
{}
|
145
|
-
when 3
|
146
|
-
{ order: :desc }
|
147
|
-
when 2
|
148
|
-
{ nulls: :first }
|
149
|
-
when 1
|
150
|
-
{ order: :desc, nulls: :last }
|
151
|
-
end
|
152
|
-
|
153
|
-
if column_position.zero?
|
154
|
-
expression = expressions_data.fetch(index[:index_oid]).shift
|
155
|
-
DbSchema::Definitions::Index::Expression.new(expression, **options)
|
156
|
-
else
|
157
|
-
DbSchema::Definitions::Index::TableField.new(column_names.fetch(column_position), **options)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
{
|
162
|
-
name: index[:name].to_sym,
|
163
|
-
columns: columns,
|
164
|
-
unique: index[:unique],
|
165
|
-
type: index[:index_type].to_sym,
|
166
|
-
condition: index[:condition]
|
167
|
-
}
|
53
|
+
def fields
|
54
|
+
fields_data.map do |field_data|
|
55
|
+
build_field(field_data)
|
168
56
|
end
|
169
57
|
end
|
170
58
|
|
171
|
-
def
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
expression_positions = positions.each_index.select { |i| positions[i].zero? }
|
59
|
+
def indexes
|
60
|
+
indexes_data.map do |index_data|
|
61
|
+
build_index(index_data)
|
62
|
+
end.sort_by(&:name)
|
63
|
+
end
|
177
64
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
65
|
+
def checks
|
66
|
+
checks_data.map do |check_data|
|
67
|
+
Definitions::CheckConstraint.new(
|
68
|
+
name: check_data[:name].to_sym,
|
69
|
+
condition: check_data[:condition]
|
70
|
+
)
|
182
71
|
end
|
72
|
+
end
|
183
73
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
Sequel.pg_array(all_positions.keys),
|
188
|
-
Sequel.pg_array((1..max_position.succ).to_a)
|
189
|
-
].each_with_object({}) do |index_data, indexes_data|
|
190
|
-
index_id = index_data[:index_id]
|
191
|
-
expressions = all_positions[index_id].map { |pos| index_data[:definitions][pos] }
|
192
|
-
|
193
|
-
indexes_data[index_id] = expressions
|
194
|
-
end
|
195
|
-
else
|
196
|
-
{}
|
74
|
+
def foreign_keys
|
75
|
+
fkeys_data.map do |foreign_key_data|
|
76
|
+
build_foreign_key(foreign_key_data)
|
197
77
|
end
|
198
78
|
end
|
199
79
|
|
200
|
-
|
80
|
+
private
|
81
|
+
def build_field(data)
|
201
82
|
type = data[:type].to_sym.downcase
|
202
83
|
if type == :'user-defined'
|
203
84
|
type = data[:custom_type_name].to_sym
|
204
85
|
end
|
205
86
|
|
87
|
+
serial_type = SERIAL_TYPES[type]
|
88
|
+
|
206
89
|
nullable = (data[:null] != 'NO')
|
207
90
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
match[:integer].to_i
|
218
|
-
elsif match[:float]
|
219
|
-
match[:float].to_f
|
220
|
-
elsif match[:boolean]
|
221
|
-
match[:boolean] == 'true'
|
222
|
-
end
|
91
|
+
if data[:is_identity] == 'YES'
|
92
|
+
type = serial_type
|
93
|
+
default = nil
|
94
|
+
elsif !data[:default].nil?
|
95
|
+
serial_field_default = "nextval('#{table_name}_#{data[:name]}_seq'::regclass)"
|
96
|
+
|
97
|
+
if !serial_type.nil? && !nullable && data[:default] == serial_field_default
|
98
|
+
type = serial_type
|
99
|
+
default = nil
|
223
100
|
else
|
224
|
-
data[:default]
|
101
|
+
default = if match = DEFAULT_VALUE.match(data[:default])
|
102
|
+
if match[:date]
|
103
|
+
Date.parse(match[:date])
|
104
|
+
elsif match[:time]
|
105
|
+
Time.parse(match[:time])
|
106
|
+
elsif match[:string]
|
107
|
+
match[:string]
|
108
|
+
elsif match[:integer]
|
109
|
+
match[:integer].to_i
|
110
|
+
elsif match[:float]
|
111
|
+
match[:float].to_f
|
112
|
+
elsif match[:boolean]
|
113
|
+
match[:boolean] == 'true'
|
114
|
+
end
|
115
|
+
else
|
116
|
+
data[:default].to_sym
|
117
|
+
end
|
225
118
|
end
|
226
119
|
end
|
227
120
|
|
@@ -263,35 +156,52 @@ GROUP BY index_id;
|
|
263
156
|
Definitions::Field.build(
|
264
157
|
data[:name].to_sym,
|
265
158
|
type,
|
266
|
-
|
267
|
-
|
268
|
-
default: default,
|
159
|
+
null: nullable,
|
160
|
+
default: default,
|
269
161
|
**options
|
270
162
|
)
|
271
163
|
end
|
272
164
|
|
273
|
-
def
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
165
|
+
def build_index(data)
|
166
|
+
columns = data[:columns].zip(data[:index_options]).map do |column, order_options|
|
167
|
+
options = case order_options
|
168
|
+
when 0
|
169
|
+
{}
|
170
|
+
when 3
|
171
|
+
{ order: :desc }
|
172
|
+
when 2
|
173
|
+
{ nulls: :first }
|
174
|
+
when 1
|
175
|
+
{ order: :desc, nulls: :last }
|
176
|
+
end
|
177
|
+
|
178
|
+
if column.is_a?(String)
|
179
|
+
DbSchema::Definitions::Index::Expression.new(column, **options)
|
180
|
+
else
|
181
|
+
DbSchema::Definitions::Index::TableField.new(column, **options)
|
182
|
+
end
|
278
183
|
end
|
279
184
|
|
280
|
-
Definitions::
|
281
|
-
name:
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
deferrable: data[:deferrable]
|
185
|
+
Definitions::Index.new(
|
186
|
+
name: data[:name].to_sym,
|
187
|
+
columns: columns,
|
188
|
+
unique: data[:unique],
|
189
|
+
primary: data[:primary],
|
190
|
+
type: data[:index_type].to_sym,
|
191
|
+
condition: data[:condition]
|
288
192
|
)
|
289
193
|
end
|
290
194
|
|
291
|
-
def
|
292
|
-
|
293
|
-
|
294
|
-
|
195
|
+
def build_foreign_key(data)
|
196
|
+
Definitions::ForeignKey.new(
|
197
|
+
name: data[:name].to_sym,
|
198
|
+
fields: data[:fields],
|
199
|
+
table: data[:referenced].to_sym,
|
200
|
+
keys: data[:keys],
|
201
|
+
on_update: FKEY_ACTIONS.fetch(data[:on_update].to_sym),
|
202
|
+
on_delete: FKEY_ACTIONS.fetch(data[:on_delete].to_sym),
|
203
|
+
deferrable: data[:deferrable]
|
204
|
+
)
|
295
205
|
end
|
296
206
|
|
297
207
|
# TODO: replace following methods with Transproc
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db_schema-reader-postgres
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vsevolod Romashov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: db_schema-definitions
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - '='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: 0.2.rc1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
54
|
+
version: 0.2.rc1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -202,12 +202,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
202
202
|
version: '0'
|
203
203
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
204
204
|
requirements:
|
205
|
-
- - "
|
205
|
+
- - ">"
|
206
206
|
- !ruby/object:Gem::Version
|
207
|
-
version:
|
207
|
+
version: 1.3.1
|
208
208
|
requirements: []
|
209
|
-
|
210
|
-
rubygems_version: 2.7.6
|
209
|
+
rubygems_version: 3.0.1
|
211
210
|
signing_key:
|
212
211
|
specification_version: 4
|
213
212
|
summary: Database schema reader for PostgreSQL
|