pg_graph 0.4.2 → 0.5.1
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/TODO +1 -0
- data/exe/pg_graph +8 -8
- data/lib/pg_graph/data/data.rb +31 -31
- data/lib/pg_graph/data/render.rb +58 -13
- data/lib/pg_graph/data/value.rb +2 -2
- data/lib/pg_graph/reflector.rb +15 -15
- data/lib/pg_graph/type/read.rb +8 -8
- data/lib/pg_graph/type/type.rb +21 -21
- data/lib/pg_graph/version.rb +1 -1
- data/lib/pg_graph.rb +4 -4
- 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: 3605f3dc16a65459725b3890e9dc85d4c7f4bf3fbdbf216526a12a1c843ef6f7
|
4
|
+
data.tar.gz: 34a6d5f23cf5914d43f53835f817aedb79f9699104c807d20d30fb9507633162
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5e870b7ecd6ec71a8c0b8e5196511963402a372374efa003c522b847ec3b92ba50904c36046451930a79f6265455f0ba33f2f65547bd6b39a79ab88dc7ba30c
|
7
|
+
data.tar.gz: ec4d637a227f5a94beda42b2075240e9ecc1d70af3eaf1fa3c9c9c7c4d5990f269b70751985aa17482f3210c3ffbb635ed92638f8d5b5d69906c7e57fcc9526e
|
data/TODO
CHANGED
data/exe/pg_graph
CHANGED
@@ -16,7 +16,7 @@ SPEC = %(
|
|
16
16
|
('psql') or by the Postgres library exec() call ('exec', 'sql'). It can also
|
17
17
|
read and write Yaml data ('yaml') that is useful for exchanging data with
|
18
18
|
other programs
|
19
|
-
|
19
|
+
|
20
20
|
Note that when you're loading or dumping data in one of the SQL formats,
|
21
21
|
you're almost always better off using postgres' own tools
|
22
22
|
(pg_dump/pg_restore/pg_sql), except in the special case when the data
|
@@ -44,8 +44,8 @@ SPEC = %(
|
|
44
44
|
Read/write reflections in the given table. The table argument can be both a
|
45
45
|
full UID (eg. "my_schema.my_reflections") or just a table name in the public
|
46
46
|
schema. Default is "public.reflections". The table and schema is created
|
47
|
-
if not present.
|
48
|
-
|
47
|
+
if not present.
|
48
|
+
|
49
49
|
If this option is used together with the --reflections option, the
|
50
50
|
reflections are read from th e given file and written back to the database.
|
51
51
|
If both options are missing, pg_graph will look for the default table and
|
@@ -74,7 +74,7 @@ SPEC = %(
|
|
74
74
|
extension but can also be set explicitly using the --format option. Reads
|
75
75
|
from standard input if FILE is missing
|
76
76
|
|
77
|
-
dump! -- DATABASE
|
77
|
+
dump! -- DATABASE
|
78
78
|
Dumps data on standard output. Default is to dump the type system in yaml
|
79
79
|
format but this can be explicitly set using the --kind and --format options
|
80
80
|
|
@@ -96,7 +96,7 @@ def load_type(timer, opts, database)
|
|
96
96
|
PgMeta.new(conn)
|
97
97
|
end
|
98
98
|
}
|
99
|
-
reflector = tg.time("reflector") {
|
99
|
+
reflector = tg.time("reflector") {
|
100
100
|
table, schema = opts.reflections_table&.split(".")&.reverse
|
101
101
|
schema ||= PgGraph::Reflector::REFLECTIONS_SCHEMA
|
102
102
|
table ||= PgGraph::Reflector::REFLECTIONS_TABLE
|
@@ -115,7 +115,7 @@ def load_type(timer, opts, database)
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
}
|
118
|
-
|
118
|
+
|
119
119
|
type = timer.time("type") { PgGraph::Type.new(meta, reflector, ignore: opts.ignore) }
|
120
120
|
[conn, type]
|
121
121
|
end
|
@@ -133,7 +133,7 @@ case opts.subcommand || :dump!
|
|
133
133
|
if opts.format?
|
134
134
|
format = opts.format
|
135
135
|
else
|
136
|
-
format =
|
136
|
+
format =
|
137
137
|
case File.extname(file)
|
138
138
|
when ".sql"; "sql"
|
139
139
|
when ".yaml", ".yml"; "yaml"
|
@@ -143,7 +143,7 @@ case opts.subcommand || :dump!
|
|
143
143
|
end
|
144
144
|
|
145
145
|
case format
|
146
|
-
when "sql", "exec";
|
146
|
+
when "sql", "exec";
|
147
147
|
connection = timer.time("connect") { PgConn.new(database) }
|
148
148
|
timer.time("load file") {
|
149
149
|
connection.exec(IO.read(file))
|
data/lib/pg_graph/data/data.rb
CHANGED
@@ -37,8 +37,8 @@ module PgGraph::Data
|
|
37
37
|
# value of a field even if the field is an association
|
38
38
|
def object() self end
|
39
39
|
|
40
|
-
def inspect(payload = inspect_inner)
|
41
|
-
"#<#{self.class}:#{uid}#{payload ? " #{payload}" : ""}>"
|
40
|
+
def inspect(payload = inspect_inner)
|
41
|
+
"#<#{self.class}:#{uid}#{payload ? " #{payload}" : ""}>"
|
42
42
|
end
|
43
43
|
|
44
44
|
def to_h() raise NotThis end
|
@@ -93,7 +93,7 @@ module PgGraph::Data
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def dup() Database.new(type, to_h) end
|
96
|
-
|
96
|
+
|
97
97
|
# Make Database pretend it is a PgGraph::Data object
|
98
98
|
def is_a?(klass) klass == PgGraph::Type or super end
|
99
99
|
|
@@ -115,7 +115,7 @@ module PgGraph::Data
|
|
115
115
|
id.nil? ? object : object[id]
|
116
116
|
end
|
117
117
|
|
118
|
-
def ==(other) to_h == other.to_h end
|
118
|
+
def ==(other) to_h == other.to_h end
|
119
119
|
|
120
120
|
alias_method :to_h, :data
|
121
121
|
|
@@ -124,17 +124,17 @@ module PgGraph::Data
|
|
124
124
|
def to_yaml() @impl.map { |k,v| [k, v.to_yaml] }.to_h end
|
125
125
|
|
126
126
|
# Note that #to_sql in derived classes should be deleted FIXME
|
127
|
-
def to_sql(format: :sql, ids: {}, delete: :all, files: [])
|
128
|
-
render = SqlRender.new(self, format, ids: ids, delete: delete, files: files)
|
127
|
+
def to_sql(format: :sql, ids: {}, delete: :all, truncate: :none, files: [])
|
128
|
+
render = SqlRender.new(self, format, ids: ids, delete: delete, truncate: truncate, files: files)
|
129
129
|
render.to_s
|
130
130
|
end
|
131
131
|
|
132
|
-
def to_exec_sql(ids: {}, delete: :all)
|
133
|
-
to_sql(format: :exec, ids: ids, delete: delete)
|
132
|
+
def to_exec_sql(ids: {}, delete: :all)
|
133
|
+
to_sql(format: :exec, ids: ids, delete: delete)
|
134
134
|
end
|
135
135
|
|
136
|
-
def to_psql_sql(files = [], ids: {}, delete: :all)
|
137
|
-
to_sql(format: :psql, ids: ids, delete: delete, files: files)
|
136
|
+
def to_psql_sql(files = [], ids: {}, delete: :all)
|
137
|
+
to_sql(format: :psql, ids: ids, delete: delete, files: files)
|
138
138
|
end
|
139
139
|
|
140
140
|
# :call-seq:
|
@@ -208,8 +208,8 @@ module PgGraph::Data
|
|
208
208
|
def data() @impl.map { |k,v| [k, v.data] }.to_h end
|
209
209
|
|
210
210
|
alias_method :to_h, :data
|
211
|
-
# def to_sql()
|
212
|
-
# tables.select { |table| !table.empty? }.map(&:to_sql).join("\n")
|
211
|
+
# def to_sql()
|
212
|
+
# tables.select { |table| !table.empty? }.map(&:to_sql).join("\n")
|
213
213
|
# end
|
214
214
|
def to_yaml() @impl.map { |k,v| [k, v.to_yaml] }.to_h end
|
215
215
|
end
|
@@ -245,29 +245,29 @@ module PgGraph::Data
|
|
245
245
|
type.fields.each { |column|
|
246
246
|
next if column.is_a?(PgGraph::Type::SimpleColumn)
|
247
247
|
that_table = db[column.type.schema.name][column.type.table.name]
|
248
|
-
association =
|
248
|
+
association =
|
249
249
|
case column
|
250
250
|
when PgGraph::Type::KindRecordColumn
|
251
251
|
KindAssociation.new(1,
|
252
|
-
self, that_table,
|
253
|
-
column.this_link_column.to_sym,
|
252
|
+
self, that_table,
|
253
|
+
column.this_link_column.to_sym,
|
254
254
|
column.that_link_column.to_sym)
|
255
255
|
when PgGraph::Type::RecordColumn
|
256
|
-
Association.new(1,
|
257
|
-
self, that_table,
|
258
|
-
column.this_link_column.to_sym,
|
256
|
+
Association.new(1,
|
257
|
+
self, that_table,
|
258
|
+
column.this_link_column.to_sym,
|
259
259
|
column.that_link_column.to_sym)
|
260
260
|
when PgGraph::Type::NmTableColumn, PgGraph::Type::MmTableColumn
|
261
261
|
dimension = column.is_a?(PgGraph::Type::NmTableColumn) ? 2 : 3
|
262
262
|
nm_table = db[column.mm_table.schema.name][column.mm_table.name]
|
263
|
-
LinkAssociation.new(dimension,
|
263
|
+
LinkAssociation.new(dimension,
|
264
264
|
self, that_table, nm_table,
|
265
|
-
column.this_link_column.to_sym, column.this_mm_column.to_sym,
|
265
|
+
column.this_link_column.to_sym, column.this_mm_column.to_sym,
|
266
266
|
column.that_mm_column.to_sym, column.that_link_column.to_sym)
|
267
267
|
when PgGraph::Type::TableColumn
|
268
|
-
Association.new(2,
|
269
|
-
self, that_table,
|
270
|
-
column.this_link_column.to_sym,
|
268
|
+
Association.new(2,
|
269
|
+
self, that_table,
|
270
|
+
column.this_link_column.to_sym,
|
271
271
|
column.that_link_column.to_sym)
|
272
272
|
else
|
273
273
|
raise NotHere
|
@@ -284,7 +284,7 @@ module PgGraph::Data
|
|
284
284
|
|
285
285
|
# Return record with the given ID
|
286
286
|
def [](id) @impl[id] end
|
287
|
-
|
287
|
+
|
288
288
|
# True if the table contains a record with the given ID
|
289
289
|
def id?(id) @impl.key?(id) end
|
290
290
|
|
@@ -348,7 +348,7 @@ module PgGraph::Data
|
|
348
348
|
uid =~ /^(.*?)\[(\d+)\]$/
|
349
349
|
[$1, $2.to_i]
|
350
350
|
end
|
351
|
-
|
351
|
+
|
352
352
|
# Redefine GUID to include ID of record
|
353
353
|
def guid() "#{table.guid}[#{id}]" end
|
354
354
|
|
@@ -371,7 +371,7 @@ module PgGraph::Data
|
|
371
371
|
constrain columns, lambda { |h| h.key?(:id) }, "No :id field"
|
372
372
|
@table = table # has to go before super
|
373
373
|
super(table.type.record_type, dimension: 1)
|
374
|
-
@impl = columns.map { |k,v| [k, Column.new(self, k, v)] }.to_h
|
374
|
+
@impl = columns.map { |k,v| [k, Column.new(self, k, v)] }.to_h
|
375
375
|
for name, association in table.associations
|
376
376
|
if association.is_a?(KindAssociation) #&& @impl.key?(name)
|
377
377
|
next if !@impl.key?(name)
|
@@ -407,9 +407,9 @@ module PgGraph::Data
|
|
407
407
|
def columns() @impl.values.select { |field| field.is_a?(Column) } end
|
408
408
|
|
409
409
|
# List of columns excluding generated columns
|
410
|
-
def value_columns()
|
410
|
+
def value_columns()
|
411
411
|
columns.select { |column| !column.type.generated? }.uniq
|
412
|
-
end
|
412
|
+
end
|
413
413
|
|
414
414
|
# List of association objects in the record
|
415
415
|
def associations() @impl.values.select { |field| field.is_a?(AssociationField) } end
|
@@ -422,7 +422,7 @@ module PgGraph::Data
|
|
422
422
|
# def data() @impl.select { |k,v| v.is_a?(Column) }.map { |k,v| [k, v.data] }.to_h end
|
423
423
|
|
424
424
|
def data()
|
425
|
-
@impl.select { |k,v| v.is_a?(Column) || v.is_a?(KindRecordField) }.map { |k,v| [k, v.data] }.to_h
|
425
|
+
@impl.select { |k,v| v.is_a?(Column) || v.is_a?(KindRecordField) }.map { |k,v| [k, v.data] }.to_h
|
426
426
|
end
|
427
427
|
|
428
428
|
alias_method :to_h, :data
|
@@ -516,7 +516,7 @@ module PgGraph::Data
|
|
516
516
|
# Return the value of the association. This is either a Record, TableValue,
|
517
517
|
# or MmTableValue depending on the dimension of the association
|
518
518
|
def object()
|
519
|
-
@object ||= Dimension.value_class(dimension).new(table, association.get_records(record))
|
519
|
+
@object ||= Dimension.value_class(dimension).new(table, association.get_records(record))
|
520
520
|
end
|
521
521
|
end
|
522
522
|
|
@@ -530,7 +530,7 @@ module PgGraph::Data
|
|
530
530
|
super(record, name, association)
|
531
531
|
@column = column
|
532
532
|
end
|
533
|
-
|
533
|
+
|
534
534
|
def value_type() @column.value_type end
|
535
535
|
def value() @column.value end
|
536
536
|
def data() @column.data end
|
data/lib/pg_graph/data/render.rb
CHANGED
@@ -16,7 +16,13 @@ module PgGraph::Data
|
|
16
16
|
# recursive - delete data for table in the fox file including recursively depending tables
|
17
17
|
# all - delete data from the whole database
|
18
18
|
attr_reader :delete
|
19
|
-
|
19
|
+
|
20
|
+
# Which data to truncate:
|
21
|
+
# none - don't delete any data
|
22
|
+
# touched - delete data for tables in the fox file
|
23
|
+
# all - delete data from the whole database
|
24
|
+
attr_reader :truncate
|
25
|
+
|
20
26
|
# +ids+ is a map from table UID to ID. Records with larger IDs will
|
21
27
|
# be emitted as insert statements, records with IDs less or equal to the
|
22
28
|
# given ID is emitted as update statements
|
@@ -25,10 +31,15 @@ module PgGraph::Data
|
|
25
31
|
# :recursive, :all Only records with an ID greater than the corresponding
|
26
32
|
# ID from +ids+ will be deleted
|
27
33
|
#
|
34
|
+
# +truncate+ acts as +delete+ that has the major drawback that it doesn't
|
35
|
+
# delete records in dependency order (FIXME This is an error). You can use
|
36
|
+
# the SQL truncate statement instead of delete using this option but note
|
37
|
+
# that +ids+ should be empty for this to work
|
38
|
+
#
|
28
39
|
# +files+ is a list of source file names to be included in the psql SQL
|
29
40
|
# header as documentation. It can be set explicitly when #to_a or #to_h is
|
30
41
|
# called (FIXME: is this used?)
|
31
|
-
def initialize(database, format, ids: {}, delete: :all, files: [])
|
42
|
+
def initialize(database, format, ids: {}, delete: :all, truncate: :none, files: [])
|
32
43
|
# puts "SqlRender#initialize"
|
33
44
|
# puts " format: #{format.inspect}"
|
34
45
|
# puts " ids: #{ids.inspect}"
|
@@ -36,10 +47,13 @@ module PgGraph::Data
|
|
36
47
|
# puts " files: #{files.inspect}"
|
37
48
|
constrain database, Database
|
38
49
|
constrain ids, { String => Integer }
|
50
|
+
constrain ids.empty? || truncate == :none, true
|
51
|
+
constrain delete == :none || truncate == :none, true
|
39
52
|
@database = database
|
40
53
|
self.format = format
|
41
54
|
(@ids = ids.dup).default = 0
|
42
55
|
@delete = delete
|
56
|
+
@truncate = truncate
|
43
57
|
@files = files
|
44
58
|
|
45
59
|
@tables = database.schemas.map(&:tables).flatten.sort
|
@@ -71,7 +85,7 @@ module PgGraph::Data
|
|
71
85
|
case format
|
72
86
|
when :sql; to_a.join("\n")
|
73
87
|
when :exec; to_a.join("\n")
|
74
|
-
when :psql; to_psql(files).map { |group| group.join("\n") }.join("\n\n")
|
88
|
+
when :psql; to_psql(files).map { |group| group.join("\n") }.join("\n\n")
|
75
89
|
end
|
76
90
|
end
|
77
91
|
|
@@ -79,6 +93,7 @@ module PgGraph::Data
|
|
79
93
|
@to_h ||= {
|
80
94
|
disable: render_triggers(:disable),
|
81
95
|
delete: render_deletes(delete),
|
96
|
+
truncate: render_truncates(truncate),
|
82
97
|
update: render_updates,
|
83
98
|
insert: render_inserts,
|
84
99
|
restart: render_restart_sequences,
|
@@ -90,7 +105,11 @@ module PgGraph::Data
|
|
90
105
|
protected
|
91
106
|
# Returns a single-element array of array of SQL statements
|
92
107
|
def to_sql
|
93
|
-
|
108
|
+
if delete != :none
|
109
|
+
[to_h[:delete] + to_h[:update] + to_h[:insert]]
|
110
|
+
else
|
111
|
+
[to_h[:truncate] + to_h[:update] + to_h[:insert]]
|
112
|
+
end
|
94
113
|
end
|
95
114
|
|
96
115
|
# Returns an array of non-empty arrays of SQL statements
|
@@ -115,7 +134,7 @@ module PgGraph::Data
|
|
115
134
|
]
|
116
135
|
end
|
117
136
|
|
118
|
-
def render_begin()
|
137
|
+
def render_begin()
|
119
138
|
[ "begin;" ]
|
120
139
|
end
|
121
140
|
|
@@ -135,7 +154,7 @@ module PgGraph::Data
|
|
135
154
|
end
|
136
155
|
|
137
156
|
def render_deletes(kind)
|
138
|
-
table_uids =
|
157
|
+
table_uids =
|
139
158
|
case kind
|
140
159
|
when :none; []
|
141
160
|
when :touched; @tables.reject(&:empty?).map(&:uid)
|
@@ -146,6 +165,8 @@ module PgGraph::Data
|
|
146
165
|
else
|
147
166
|
raise ArgumentError
|
148
167
|
end
|
168
|
+
|
169
|
+
# FIXME: Not in dependency order
|
149
170
|
table_uids.map { |uid|
|
150
171
|
if !@ids.key?(uid)
|
151
172
|
"delete from #{uid};"
|
@@ -155,14 +176,38 @@ module PgGraph::Data
|
|
155
176
|
}
|
156
177
|
end
|
157
178
|
|
179
|
+
def render_truncates(kind)
|
180
|
+
table_uids =
|
181
|
+
case kind
|
182
|
+
when :none; []
|
183
|
+
when :touched; @tables.reject(&:empty?).map(&:uid)
|
184
|
+
when :all; @tables.map(&:uid)
|
185
|
+
else
|
186
|
+
raise ArgumentError
|
187
|
+
end
|
188
|
+
table_uids.map { |uid| "truncate #{uid} cascade;" }
|
189
|
+
end
|
190
|
+
|
158
191
|
def render_updates
|
159
192
|
@update_records.map { |record|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
193
|
+
# Temporary fix for the case where a kind field is updated. Kind fields
|
194
|
+
# are not considered value_columns (!) so kind fields are skipped in
|
195
|
+
# the original code below. FIXME FIXME FIXME
|
196
|
+
"update #{record.table.uid} set " +
|
197
|
+
record.to_h.keys
|
198
|
+
.map { |key| record[key] }
|
199
|
+
.reject { |column| column.type.primary_key? }
|
200
|
+
.map { |column|
|
201
|
+
"#{column.name} = #{render_value(column)}"
|
202
|
+
}.join(", ") + " " \
|
203
|
+
+ "where id = #{record.id};"
|
204
|
+
|
205
|
+
# "update #{record.table.uid} set " \
|
206
|
+
# + record.value_columns
|
207
|
+
# .select { |column| !column.type.primary_key? }
|
208
|
+
# .map { |column| "#{column.name} = #{render_value(column)}" }
|
209
|
+
# .join(", ") + " " \
|
210
|
+
# + "where id = #{record.id};"
|
166
211
|
}
|
167
212
|
end
|
168
213
|
|
@@ -229,7 +274,7 @@ module PgGraph::Data
|
|
229
274
|
end
|
230
275
|
end
|
231
276
|
|
232
|
-
def render_commit()
|
277
|
+
def render_commit()
|
233
278
|
[ "commit;" ]
|
234
279
|
end
|
235
280
|
end
|
data/lib/pg_graph/data/value.rb
CHANGED
@@ -9,7 +9,7 @@ module PgGraph::Data
|
|
9
9
|
|
10
10
|
# Fake class: RecordValue.new(table, records) simply returns the Record object
|
11
11
|
class RecordValue < Value
|
12
|
-
def self.new(table, records)
|
12
|
+
def self.new(table, records)
|
13
13
|
constrain table, Table
|
14
14
|
constrain records, [Record]
|
15
15
|
records.first
|
@@ -50,7 +50,7 @@ module PgGraph::Data
|
|
50
50
|
@impl = {}
|
51
51
|
records.each { |record| (@impl[record.id] ||= []) << record }
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
# Number of records including duplicates
|
55
55
|
def size() records.size end
|
56
56
|
|
data/lib/pg_graph/reflector.rb
CHANGED
@@ -10,7 +10,7 @@ module PgGraph
|
|
10
10
|
# Template for 'this' field name. Can be nil
|
11
11
|
attr_reader :this
|
12
12
|
|
13
|
-
# Template for 'that' field name or false if the field
|
13
|
+
# Template for 'that' field name or false if the field should not be
|
14
14
|
# included in the model. Can be nil
|
15
15
|
attr_reader :that
|
16
16
|
|
@@ -30,7 +30,7 @@ module PgGraph
|
|
30
30
|
attr_reader :pluralize
|
31
31
|
|
32
32
|
# RE corresponding to #match. #re always match a full UID
|
33
|
-
attr_reader :re
|
33
|
+
attr_reader :re
|
34
34
|
|
35
35
|
# Number of name components (database, schema, table, column). It can be
|
36
36
|
# between one and four. By ordering reflections from highest to lowest
|
@@ -67,9 +67,9 @@ module PgGraph
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def to_yaml
|
70
|
-
{
|
71
|
-
match: match, this: this, that: that, multi: multi, pluralize: pluralize,
|
72
|
-
default_reflection: default_reflection
|
70
|
+
{
|
71
|
+
match: match, this: this, that: that, multi: multi, pluralize: pluralize,
|
72
|
+
default_reflection: default_reflection
|
73
73
|
}
|
74
74
|
end
|
75
75
|
|
@@ -82,8 +82,8 @@ module PgGraph
|
|
82
82
|
# +hash+ has the keys :match, :this, :that, and :pluralize. The keys can
|
83
83
|
# also be strings
|
84
84
|
def self.load_yaml(hash)
|
85
|
-
Reflection.new *METHODS.map { |key|
|
86
|
-
value = hash[key].nil? ? hash[key.to_s] : hash[key]
|
85
|
+
Reflection.new *METHODS.map { |key|
|
86
|
+
value = hash[key].nil? ? hash[key.to_s] : hash[key]
|
87
87
|
value == "nil" ? nil : value
|
88
88
|
}
|
89
89
|
end
|
@@ -117,7 +117,7 @@ module PgGraph
|
|
117
117
|
def dup() Reflector.new(reflections.dup) end
|
118
118
|
|
119
119
|
# Return true if the Reflector has no reflections
|
120
|
-
def empty?()
|
120
|
+
def empty?()
|
121
121
|
@reflection_list ? reflections.empty? : !@reflections.values.all?(:empty?)
|
122
122
|
end
|
123
123
|
|
@@ -126,8 +126,8 @@ module PgGraph
|
|
126
126
|
def add(*reflections)
|
127
127
|
@reflection_list = nil
|
128
128
|
# reverse makes it possible to use #insert but keep order:
|
129
|
-
Array(reflections).flatten.reverse.each { |reflection|
|
130
|
-
@reflections[reflection.components].insert(0, reflection)
|
129
|
+
Array(reflections).flatten.reverse.each { |reflection|
|
130
|
+
@reflections[reflection.components].insert(0, reflection)
|
131
131
|
}
|
132
132
|
end
|
133
133
|
|
@@ -193,14 +193,14 @@ module PgGraph
|
|
193
193
|
table ||= REFLECTIONS_TABLE
|
194
194
|
self.class.ensure_table(conn, schema, table)
|
195
195
|
values = reflections.select { |r| !r.default_reflection }.map.with_index { |reflection, i|
|
196
|
-
values = "(" + Reflection::METHODS.map { |m|
|
196
|
+
values = "(" + Reflection::METHODS.map { |m|
|
197
197
|
v = reflection.send(m)
|
198
198
|
v.nil? ? "null" : "'#{v}'"
|
199
199
|
}.join(", ") + ", #{i})"
|
200
200
|
}.join(",\n")
|
201
201
|
|
202
202
|
conn.exec %(
|
203
|
-
insert into #{schema}.#{table}
|
203
|
+
insert into #{schema}.#{table}
|
204
204
|
(match, this, that, multi, pluralize, default_reflection, ordinal)
|
205
205
|
values
|
206
206
|
#{values}
|
@@ -215,14 +215,14 @@ module PgGraph
|
|
215
215
|
{"match"=>"/parent_(\\w+)_id/", "that"=>"child_$1"},
|
216
216
|
{"match"=>"/child_(\\w+)_id/", "that"=>"parent_$1"},
|
217
217
|
{"match"=>"kind", "this"=>"kind", "that"=>"$$"},
|
218
|
-
{"match"=>"/(\\w+)_kind/", "this"=>"$1", "that"=>"$$"},
|
218
|
+
{"match"=>"/(\\w+)_kind/", "this"=>"$1", "that"=>"$$"},
|
219
219
|
{"match"=>"/(\\w+)_by_id/", "this"=>"$1_by", "that"=>"$1_$$", pluralize: true},
|
220
220
|
{"match"=>"/(\\w+)_id/", "this"=>"$1", "that"=>"$$", multi: false},
|
221
221
|
{"match"=>"/(\\w+)_id/", "this"=>"$1", "that"=>"$1_of", multi: true, pluralize: false},
|
222
222
|
{"match"=>"/(\\w+)/", "this"=>"$1", "that"=>"$$"}, # Kind fields w/o explicit 'kind'
|
223
223
|
]
|
224
|
-
initializers.map { |initializer|
|
225
|
-
Reflection.load_yaml initializer.merge(default_reflection: true)
|
224
|
+
initializers.map { |initializer|
|
225
|
+
Reflection.load_yaml initializer.merge(default_reflection: true)
|
226
226
|
}
|
227
227
|
end
|
228
228
|
end
|
data/lib/pg_graph/type/read.rb
CHANGED
@@ -7,7 +7,7 @@ module PgGraph::Type
|
|
7
7
|
# Array of [record, meta_column] tuples
|
8
8
|
field_columns = []
|
9
9
|
link_columns = []
|
10
|
-
kind_columns = [] # The link side
|
10
|
+
kind_columns = [] # The link side
|
11
11
|
id_link_columns = [] # sub tables
|
12
12
|
|
13
13
|
# Temporary arrays of meta tables
|
@@ -21,7 +21,7 @@ module PgGraph::Type
|
|
21
21
|
meta_schema.tables.values.select { |t| t.table? }.each { |meta_table| # FIXME Ignore views for now
|
22
22
|
(meta_table.mm_table? ? mm_tables : tables) << meta_table
|
23
23
|
table = Table.new(
|
24
|
-
schema, meta_table.name,
|
24
|
+
schema, meta_table.name,
|
25
25
|
mm_table: meta_table.mm_table?,
|
26
26
|
depending_materialized_views: meta_table.depending_views.select(&:materialized?))
|
27
27
|
record_type = RecordType.new(table)
|
@@ -32,7 +32,7 @@ module PgGraph::Type
|
|
32
32
|
# Create basic types needed by columns
|
33
33
|
type_name = meta_column.type
|
34
34
|
if !schema.key?(type_name) && !catalog.key?(type_name)
|
35
|
-
if meta_column.array?
|
35
|
+
if meta_column.array?
|
36
36
|
element_name = meta_column.element_type
|
37
37
|
dimensions = meta_column.dimensions
|
38
38
|
if !schema.key?(element_name) && !catalog.key?(element_name)
|
@@ -51,7 +51,7 @@ module PgGraph::Type
|
|
51
51
|
if meta_column.name == "id"
|
52
52
|
id_link_columns
|
53
53
|
elsif meta_column.name =~ /^(?:.*_)?kind$/
|
54
|
-
kind_columns
|
54
|
+
kind_columns
|
55
55
|
else
|
56
56
|
link_columns
|
57
57
|
end
|
@@ -76,7 +76,7 @@ module PgGraph::Type
|
|
76
76
|
next if meta_column.kind?
|
77
77
|
type = record_type.schema[meta_column.type] || catalog[meta_column.type]
|
78
78
|
SimpleColumn.new(
|
79
|
-
record_type, meta_column.name, meta_column.name, type,
|
79
|
+
record_type, meta_column.name, meta_column.name, type,
|
80
80
|
ordinal: meta_column.ordinal,
|
81
81
|
**column_options(meta_column))
|
82
82
|
}
|
@@ -104,7 +104,7 @@ module PgGraph::Type
|
|
104
104
|
(reference_count[record_type] ||= {})[type] ||= 0
|
105
105
|
reference_count[record_type][type] += 1 if reflector.multi?(this_link_column)
|
106
106
|
|
107
|
-
field =
|
107
|
+
field =
|
108
108
|
if meta_column.kind?
|
109
109
|
name = reflector.this(meta_column.uid) || meta_column.name
|
110
110
|
name = meta_column.name if record_type[name] # Check for duplicates
|
@@ -171,7 +171,7 @@ module PgGraph::Type
|
|
171
171
|
# Create back-references
|
172
172
|
if this_column.unique?
|
173
173
|
RecordColumn.new(
|
174
|
-
that_record_type, name, nil, this_record_type,
|
174
|
+
that_record_type, name, nil, this_record_type,
|
175
175
|
this_column.that_link_column, this_column.this_link_column)
|
176
176
|
else
|
177
177
|
TableColumn.new(that_record_type, name, this_table.type,
|
@@ -237,7 +237,7 @@ module PgGraph::Type
|
|
237
237
|
if table1.type.record_type.key?(column1_name)
|
238
238
|
raise Error, "Duplicate column name in #{table1.identifier}: #{column1_name}"
|
239
239
|
end
|
240
|
-
|
240
|
+
|
241
241
|
if table2.type.record_type.key?(column2_name)
|
242
242
|
raise Error, "Duplicate column name in #{table2.identifier}: #{column2_name}"
|
243
243
|
end
|
data/lib/pg_graph/type/type.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
module PgGraph::Type
|
3
3
|
class Error < StandardError; end
|
4
|
-
|
4
|
+
|
5
5
|
class Node < HashTree::Set
|
6
6
|
include Constrain
|
7
7
|
|
@@ -16,7 +16,7 @@ module PgGraph::Type
|
|
16
16
|
# The full Ruby model identifier of the object within a database. It
|
17
17
|
# corresponds to #uid
|
18
18
|
def schema_identifier() identifier end
|
19
|
-
|
19
|
+
|
20
20
|
# :call-seq: initialize(database, name, attach: true)
|
21
21
|
def initialize(parent, name, **opts)
|
22
22
|
constrain parent, Node, NilClass
|
@@ -24,8 +24,8 @@ module PgGraph::Type
|
|
24
24
|
super
|
25
25
|
end
|
26
26
|
|
27
|
-
def inspect(payload = inspect_inner)
|
28
|
-
"#<#{self.class}:#{name.inspect}#{payload ? " #{payload}" : ""}>"
|
27
|
+
def inspect(payload = inspect_inner)
|
28
|
+
"#<#{self.class}:#{name.inspect}#{payload ? " #{payload}" : ""}>"
|
29
29
|
end
|
30
30
|
|
31
31
|
def inspect_inner() nil end
|
@@ -33,9 +33,9 @@ module PgGraph::Type
|
|
33
33
|
protected
|
34
34
|
# Nodes with nil keys are not attached. This is used in PgCatalogSchema to
|
35
35
|
# avoid being included in the list of schemas
|
36
|
-
def do_attach(key, child)
|
36
|
+
def do_attach(key, child)
|
37
37
|
!key?(key) or raise PgGraph::Error, "Duplicate fields in #{self.uid}: '#{key}'"
|
38
|
-
super if child
|
38
|
+
super if child
|
39
39
|
end
|
40
40
|
|
41
41
|
# Forward list of methods to object. The arguments should be strings or symbols
|
@@ -48,7 +48,7 @@ module PgGraph::Type
|
|
48
48
|
|
49
49
|
# Included by tables, records, and fields
|
50
50
|
module TableObject
|
51
|
-
# Circular definitions. Classes that include TableObject should redefine at least
|
51
|
+
# Circular definitions. Classes that include TableObject should redefine at least
|
52
52
|
# one of the methods to break the loop
|
53
53
|
def table() record_type.table end
|
54
54
|
def table_type() table.type end
|
@@ -95,7 +95,7 @@ module PgGraph::Type
|
|
95
95
|
@reflector = reflector || @reflector
|
96
96
|
case arg
|
97
97
|
# #read_meta is a member of Database but defined in read.rb
|
98
|
-
when PgMeta; read_meta(arg, ignore: ignore)
|
98
|
+
when PgMeta; read_meta(arg, ignore: ignore)
|
99
99
|
when PgConn; read_meta(PgMeta.new(arg), ignore: ignore)
|
100
100
|
end
|
101
101
|
end
|
@@ -282,12 +282,12 @@ module PgGraph::Type
|
|
282
282
|
end
|
283
283
|
|
284
284
|
# List of postgres columns. The columns are sorted by ordinal
|
285
|
-
def columns()
|
285
|
+
def columns()
|
286
286
|
@columns ||= begin
|
287
287
|
cols = fields.map { |field|
|
288
288
|
case field
|
289
289
|
when SimpleColumn; field
|
290
|
-
when KindRecordColumn;
|
290
|
+
when KindRecordColumn;
|
291
291
|
if field.kind_column&.parent
|
292
292
|
nil
|
293
293
|
else
|
@@ -308,7 +308,7 @@ module PgGraph::Type
|
|
308
308
|
cols = fields.map { |field|
|
309
309
|
case field
|
310
310
|
when SimpleColumn; field
|
311
|
-
when KindRecordColumn;
|
311
|
+
when KindRecordColumn;
|
312
312
|
if field.kind_column&.parent
|
313
313
|
nil
|
314
314
|
else
|
@@ -324,7 +324,7 @@ module PgGraph::Type
|
|
324
324
|
end
|
325
325
|
|
326
326
|
# TODO: Rename #columns to #postgres_columns and #abstract_columns to #columns
|
327
|
-
def abstract_columns
|
327
|
+
def abstract_columns
|
328
328
|
@abstract_columns ||= fields.map { |field|
|
329
329
|
case field
|
330
330
|
when SimpleColumn; field
|
@@ -334,19 +334,19 @@ module PgGraph::Type
|
|
334
334
|
nil
|
335
335
|
end
|
336
336
|
}.compact.sort_by(&:ordinal)
|
337
|
-
|
337
|
+
|
338
338
|
end
|
339
339
|
|
340
340
|
# List of columns excluding generated fields
|
341
|
-
def value_columns()
|
341
|
+
def value_columns()
|
342
342
|
columns.select { |column| !column.generated? }
|
343
343
|
end
|
344
344
|
|
345
345
|
# True iff name if the name of a postgres column
|
346
346
|
# def column?(name) self[name].is_a?(SimpleColumn) end
|
347
|
-
def column?(name)
|
347
|
+
def column?(name)
|
348
348
|
raise "See the rename TODO above"
|
349
|
-
@columns_hash.key?(name)
|
349
|
+
@columns_hash.key?(name)
|
350
350
|
end
|
351
351
|
|
352
352
|
end
|
@@ -439,7 +439,7 @@ module PgGraph::Type
|
|
439
439
|
def primary_key?() @postgres_column && @primary_key end
|
440
440
|
|
441
441
|
# Return true/false or nil if postgres_column is an identity column.
|
442
|
-
# Sub-keys are primary keys but not identity keys
|
442
|
+
# Sub-keys are primary keys but not identity keys
|
443
443
|
def identity?() @postgres_column && @identity end
|
444
444
|
|
445
445
|
# Return true/false or nil
|
@@ -462,8 +462,8 @@ module PgGraph::Type
|
|
462
462
|
|
463
463
|
protected
|
464
464
|
def initialize(
|
465
|
-
record_type, name, postgres_column, type,
|
466
|
-
primary_key: false, identity: false,
|
465
|
+
record_type, name, postgres_column, type,
|
466
|
+
primary_key: false, identity: false,
|
467
467
|
reference: false, kind: false,
|
468
468
|
nullable: true, unique: false, readonly: false, generated: false)
|
469
469
|
constrain record_type, RecordType, NilClass
|
@@ -531,8 +531,8 @@ module PgGraph::Type
|
|
531
531
|
forward_method :kind_column, :literal?
|
532
532
|
|
533
533
|
def initialize(
|
534
|
-
record_type, name, postgres_column, type,
|
535
|
-
this_link_column, that_link_column,
|
534
|
+
record_type, name, postgres_column, type,
|
535
|
+
this_link_column, that_link_column,
|
536
536
|
kind_column, **opts)
|
537
537
|
constrain kind_column, SimpleColumn
|
538
538
|
super(record_type, name, postgres_column, type, this_link_column, that_link_column, kind: true, **opts)
|
data/lib/pg_graph/version.rb
CHANGED
data/lib/pg_graph.rb
CHANGED
@@ -53,12 +53,12 @@ module PgGraph
|
|
53
53
|
def self.new(arg, reflections = nil, schema = nil, ignore: [])
|
54
54
|
constrain arg, PgMeta, PgConn
|
55
55
|
constrain reflections, Reflector, Array, String, PgConn, NilClass
|
56
|
-
meta =
|
56
|
+
meta =
|
57
57
|
case arg
|
58
58
|
when PgMeta; arg
|
59
59
|
when PgConn; PgMeta.new(arg)
|
60
60
|
end
|
61
|
-
reflector =
|
61
|
+
reflector =
|
62
62
|
case reflections
|
63
63
|
when Reflector; reflections
|
64
64
|
when Array; Reflector.load_yaml(reflections)
|
@@ -78,7 +78,7 @@ module PgGraph
|
|
78
78
|
# instantiate(hash)
|
79
79
|
# instantiate(yaml)
|
80
80
|
# instantiate(pg_conn)
|
81
|
-
#
|
81
|
+
#
|
82
82
|
def instantiate(arg = nil)
|
83
83
|
constrain arg, NilClass, Hash, PgConn
|
84
84
|
Data.new(self, arg)
|
@@ -94,7 +94,7 @@ module PgGraph
|
|
94
94
|
# new(type, hash = {})
|
95
95
|
# new(type, yaml = {})
|
96
96
|
# new(type, pg_conn = nil)
|
97
|
-
#
|
97
|
+
#
|
98
98
|
# Note that together with ::=== and Data::Database#is_a? this makes
|
99
99
|
# Data::Database pretend it is an instance of the Data module
|
100
100
|
def self.new(type, arg)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_graph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: boolean
|