pg_graph 0.5.0 → 0.5.2
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/exe/pg_graph +10 -8
- data/lib/pg_graph/data/data.rb +29 -29
- data/lib/pg_graph/data/render.rb +23 -11
- data/lib/pg_graph/data/value.rb +2 -2
- data/lib/pg_graph/reflector.rb +30 -18
- data/lib/pg_graph/type/read.rb +10 -10
- 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: 38b9eb4ca9867310cda60284befd00b8819dd91ab0f337c053a47e2045c41f35
|
4
|
+
data.tar.gz: f4fe9a924423df0b43b3e0609ba3075e864902ff7a6e92d1c7d2baf522065f31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f057d02742170bfb37e2fc93e6c1419c65ca8081e8543c33c497e29efa82598c9cb82ef10b3359143b7ad56482328de8c8b8e59b75749f89df940b355fe874f9
|
7
|
+
data.tar.gz: 37e9bc383ef07636a85740dd73350ba7dacd8b67036250b0959b41b31f4d91afef540f8ae4b841dbbbc513b50bd5b439e1b63230175a407d00cfd364302418a0
|
data/exe/pg_graph
CHANGED
@@ -11,12 +11,14 @@ include ShellOpts
|
|
11
11
|
SPEC = %(
|
12
12
|
@ Load, dump, and clean databases
|
13
13
|
|
14
|
+
-- DATABASE
|
15
|
+
|
14
16
|
pg_graph is a utility that uses the PgGraph module to load, dump, or clean a
|
15
17
|
database. It uses a variety of formats that can be executed by psql(1)
|
16
18
|
('psql') or by the Postgres library exec() call ('exec', 'sql'). It can also
|
17
19
|
read and write Yaml data ('yaml') that is useful for exchanging data with
|
18
20
|
other programs
|
19
|
-
|
21
|
+
|
20
22
|
Note that when you're loading or dumping data in one of the SQL formats,
|
21
23
|
you're almost always better off using postgres' own tools
|
22
24
|
(pg_dump/pg_restore/pg_sql), except in the special case when the data
|
@@ -44,8 +46,8 @@ SPEC = %(
|
|
44
46
|
Read/write reflections in the given table. The table argument can be both a
|
45
47
|
full UID (eg. "my_schema.my_reflections") or just a table name in the public
|
46
48
|
schema. Default is "public.reflections". The table and schema is created
|
47
|
-
if not present.
|
48
|
-
|
49
|
+
if not present.
|
50
|
+
|
49
51
|
If this option is used together with the --reflections option, the
|
50
52
|
reflections are read from th e given file and written back to the database.
|
51
53
|
If both options are missing, pg_graph will look for the default table and
|
@@ -74,7 +76,7 @@ SPEC = %(
|
|
74
76
|
extension but can also be set explicitly using the --format option. Reads
|
75
77
|
from standard input if FILE is missing
|
76
78
|
|
77
|
-
dump! -- DATABASE
|
79
|
+
dump! -- DATABASE
|
78
80
|
Dumps data on standard output. Default is to dump the type system in yaml
|
79
81
|
format but this can be explicitly set using the --kind and --format options
|
80
82
|
|
@@ -96,7 +98,7 @@ def load_type(timer, opts, database)
|
|
96
98
|
PgMeta.new(conn)
|
97
99
|
end
|
98
100
|
}
|
99
|
-
reflector = tg.time("reflector") {
|
101
|
+
reflector = tg.time("reflector") {
|
100
102
|
table, schema = opts.reflections_table&.split(".")&.reverse
|
101
103
|
schema ||= PgGraph::Reflector::REFLECTIONS_SCHEMA
|
102
104
|
table ||= PgGraph::Reflector::REFLECTIONS_TABLE
|
@@ -115,7 +117,7 @@ def load_type(timer, opts, database)
|
|
115
117
|
end
|
116
118
|
end
|
117
119
|
}
|
118
|
-
|
120
|
+
|
119
121
|
type = timer.time("type") { PgGraph::Type.new(meta, reflector, ignore: opts.ignore) }
|
120
122
|
[conn, type]
|
121
123
|
end
|
@@ -133,7 +135,7 @@ case opts.subcommand || :dump!
|
|
133
135
|
if opts.format?
|
134
136
|
format = opts.format
|
135
137
|
else
|
136
|
-
format =
|
138
|
+
format =
|
137
139
|
case File.extname(file)
|
138
140
|
when ".sql"; "sql"
|
139
141
|
when ".yaml", ".yml"; "yaml"
|
@@ -143,7 +145,7 @@ case opts.subcommand || :dump!
|
|
143
145
|
end
|
144
146
|
|
145
147
|
case format
|
146
|
-
when "sql", "exec";
|
148
|
+
when "sql", "exec";
|
147
149
|
connection = timer.time("connect") { PgConn.new(database) }
|
148
150
|
timer.time("load file") {
|
149
151
|
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
|
|
@@ -129,12 +129,12 @@ module PgGraph::Data
|
|
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
@@ -85,7 +85,7 @@ module PgGraph::Data
|
|
85
85
|
case format
|
86
86
|
when :sql; to_a.join("\n")
|
87
87
|
when :exec; to_a.join("\n")
|
88
|
-
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")
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
@@ -134,7 +134,7 @@ module PgGraph::Data
|
|
134
134
|
]
|
135
135
|
end
|
136
136
|
|
137
|
-
def render_begin()
|
137
|
+
def render_begin()
|
138
138
|
[ "begin;" ]
|
139
139
|
end
|
140
140
|
|
@@ -154,7 +154,7 @@ module PgGraph::Data
|
|
154
154
|
end
|
155
155
|
|
156
156
|
def render_deletes(kind)
|
157
|
-
table_uids =
|
157
|
+
table_uids =
|
158
158
|
case kind
|
159
159
|
when :none; []
|
160
160
|
when :touched; @tables.reject(&:empty?).map(&:uid)
|
@@ -177,7 +177,7 @@ module PgGraph::Data
|
|
177
177
|
end
|
178
178
|
|
179
179
|
def render_truncates(kind)
|
180
|
-
table_uids =
|
180
|
+
table_uids =
|
181
181
|
case kind
|
182
182
|
when :none; []
|
183
183
|
when :touched; @tables.reject(&:empty?).map(&:uid)
|
@@ -190,12 +190,24 @@ module PgGraph::Data
|
|
190
190
|
|
191
191
|
def render_updates
|
192
192
|
@update_records.map { |record|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
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};"
|
199
211
|
}
|
200
212
|
end
|
201
213
|
|
@@ -262,7 +274,7 @@ module PgGraph::Data
|
|
262
274
|
end
|
263
275
|
end
|
264
276
|
|
265
|
-
def render_commit()
|
277
|
+
def render_commit()
|
266
278
|
[ "commit;" ]
|
267
279
|
end
|
268
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
@@ -2,6 +2,12 @@
|
|
2
2
|
require 'constrain'
|
3
3
|
require 'indented_io'
|
4
4
|
|
5
|
+
def putv(*variables)
|
6
|
+
for var in Array(variables)
|
7
|
+
puts "#{var}: #{self.send(var).inspect}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
module PgGraph
|
6
12
|
class Reflection
|
7
13
|
# Textual representation of match RE (String)
|
@@ -30,7 +36,7 @@ module PgGraph
|
|
30
36
|
attr_reader :pluralize
|
31
37
|
|
32
38
|
# RE corresponding to #match. #re always match a full UID
|
33
|
-
attr_reader :re
|
39
|
+
attr_reader :re
|
34
40
|
|
35
41
|
# Number of name components (database, schema, table, column). It can be
|
36
42
|
# between one and four. By ordering reflections from highest to lowest
|
@@ -41,6 +47,11 @@ module PgGraph
|
|
41
47
|
# True if this is a default reflection
|
42
48
|
attr_reader :default_reflection
|
43
49
|
|
50
|
+
def dump
|
51
|
+
puts "Reflection"
|
52
|
+
indent { putv :match, :re, :this, :that, :multi?, :pluralize, :components }
|
53
|
+
end
|
54
|
+
|
44
55
|
# +this+ and +that+ are template strings, nil, or false
|
45
56
|
def initialize(match, this, that, multi = nil, pluralize = nil, default_reflection = false)
|
46
57
|
constrain match, Regexp, String
|
@@ -67,9 +78,9 @@ module PgGraph
|
|
67
78
|
end
|
68
79
|
|
69
80
|
def to_yaml
|
70
|
-
{
|
71
|
-
match: match, this: this, that: that, multi: multi, pluralize: pluralize,
|
72
|
-
default_reflection: default_reflection
|
81
|
+
{
|
82
|
+
match: match, this: this, that: that, multi: multi, pluralize: pluralize,
|
83
|
+
default_reflection: default_reflection
|
73
84
|
}
|
74
85
|
end
|
75
86
|
|
@@ -82,8 +93,8 @@ module PgGraph
|
|
82
93
|
# +hash+ has the keys :match, :this, :that, and :pluralize. The keys can
|
83
94
|
# also be strings
|
84
95
|
def self.load_yaml(hash)
|
85
|
-
Reflection.new *METHODS.map { |key|
|
86
|
-
value = hash[key].nil? ? hash[key.to_s] : hash[key]
|
96
|
+
Reflection.new *METHODS.map { |key|
|
97
|
+
value = hash[key].nil? ? hash[key.to_s] : hash[key]
|
87
98
|
value == "nil" ? nil : value
|
88
99
|
}
|
89
100
|
end
|
@@ -117,7 +128,7 @@ module PgGraph
|
|
117
128
|
def dup() Reflector.new(reflections.dup) end
|
118
129
|
|
119
130
|
# Return true if the Reflector has no reflections
|
120
|
-
def empty?()
|
131
|
+
def empty?()
|
121
132
|
@reflection_list ? reflections.empty? : !@reflections.values.all?(:empty?)
|
122
133
|
end
|
123
134
|
|
@@ -126,8 +137,8 @@ module PgGraph
|
|
126
137
|
def add(*reflections)
|
127
138
|
@reflection_list = nil
|
128
139
|
# reverse makes it possible to use #insert but keep order:
|
129
|
-
Array(reflections).flatten.reverse.each { |reflection|
|
130
|
-
@reflections[reflection.components].insert(0, reflection)
|
140
|
+
Array(reflections).flatten.reverse.each { |reflection|
|
141
|
+
@reflections[reflection.components].insert(0, reflection)
|
131
142
|
}
|
132
143
|
end
|
133
144
|
|
@@ -141,10 +152,11 @@ module PgGraph
|
|
141
152
|
|
142
153
|
# Find 'that' field name for the given UID by searching through reflections
|
143
154
|
# for a match. The name is pluralized if the matcher returns true or if the
|
144
|
-
# matcher returns nil and unique is false The :table option can be used to
|
155
|
+
# matcher returns nil and unique is false. The :table option can be used to
|
145
156
|
# override the table name in '$$' rules. This is used in N:M and M:M
|
146
|
-
# relations. Returns
|
147
|
-
#
|
157
|
+
# relations. Returns false if the :that property is set to false in the
|
158
|
+
# reflections file. Returns nil if no match was found or if a matching
|
159
|
+
# reflection has #continue equal to false
|
148
160
|
def that(uid, unique, multi = false, table: nil)
|
149
161
|
constrain uid, String
|
150
162
|
if (name, pluralize = do_match(uid, :that, multi, table: table))
|
@@ -193,14 +205,14 @@ module PgGraph
|
|
193
205
|
table ||= REFLECTIONS_TABLE
|
194
206
|
self.class.ensure_table(conn, schema, table)
|
195
207
|
values = reflections.select { |r| !r.default_reflection }.map.with_index { |reflection, i|
|
196
|
-
values = "(" + Reflection::METHODS.map { |m|
|
208
|
+
values = "(" + Reflection::METHODS.map { |m|
|
197
209
|
v = reflection.send(m)
|
198
210
|
v.nil? ? "null" : "'#{v}'"
|
199
211
|
}.join(", ") + ", #{i})"
|
200
212
|
}.join(",\n")
|
201
213
|
|
202
214
|
conn.exec %(
|
203
|
-
insert into #{schema}.#{table}
|
215
|
+
insert into #{schema}.#{table}
|
204
216
|
(match, this, that, multi, pluralize, default_reflection, ordinal)
|
205
217
|
values
|
206
218
|
#{values}
|
@@ -215,14 +227,14 @@ module PgGraph
|
|
215
227
|
{"match"=>"/parent_(\\w+)_id/", "that"=>"child_$1"},
|
216
228
|
{"match"=>"/child_(\\w+)_id/", "that"=>"parent_$1"},
|
217
229
|
{"match"=>"kind", "this"=>"kind", "that"=>"$$"},
|
218
|
-
{"match"=>"/(\\w+)_kind/", "this"=>"$1", "that"=>"$$"},
|
230
|
+
{"match"=>"/(\\w+)_kind/", "this"=>"$1", "that"=>"$$"},
|
219
231
|
{"match"=>"/(\\w+)_by_id/", "this"=>"$1_by", "that"=>"$1_$$", pluralize: true},
|
220
232
|
{"match"=>"/(\\w+)_id/", "this"=>"$1", "that"=>"$$", multi: false},
|
221
233
|
{"match"=>"/(\\w+)_id/", "this"=>"$1", "that"=>"$1_of", multi: true, pluralize: false},
|
222
234
|
{"match"=>"/(\\w+)/", "this"=>"$1", "that"=>"$$"}, # Kind fields w/o explicit 'kind'
|
223
235
|
]
|
224
|
-
initializers.map { |initializer|
|
225
|
-
Reflection.load_yaml initializer.merge(default_reflection: true)
|
236
|
+
initializers.map { |initializer|
|
237
|
+
Reflection.load_yaml initializer.merge(default_reflection: true)
|
226
238
|
}
|
227
239
|
end
|
228
240
|
end
|
@@ -240,7 +252,7 @@ module PgGraph
|
|
240
252
|
match_data = reflection.re.match(uid) or next
|
241
253
|
template = reflection.send(kind).dup
|
242
254
|
if template == false
|
243
|
-
return
|
255
|
+
return [false, false]
|
244
256
|
elsif template
|
245
257
|
table ||= uid.split(".")[-2]
|
246
258
|
template.gsub!(/\$\$/, table)
|
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
|
@@ -144,10 +144,10 @@ module PgGraph::Type
|
|
144
144
|
else
|
145
145
|
multi = reference_count[this_record_type][that_record_type] > 1
|
146
146
|
name = reflector.that(uid, this_column.unique?, multi, table: this_record_type.name)
|
147
|
-
name ||= PgGraph.inflector.pluralize(this_column.table.name) if this_column.kind?
|
147
|
+
name ||= PgGraph.inflector.pluralize(this_column.table.name) if name.nil? && this_column.kind?
|
148
148
|
end
|
149
149
|
|
150
|
-
next if name
|
150
|
+
next if !name
|
151
151
|
|
152
152
|
# Check for name collisions
|
153
153
|
if that_record_type.key?(name)
|
@@ -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.5.
|
4
|
+
version: 0.5.2
|
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-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: boolean
|