pg_graph 0.1.2 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/pg_graph +40 -7
- data/lib/pg_graph/inflector.rb +1 -1
- data/lib/pg_graph/reflector.rb +71 -5
- data/lib/pg_graph/version.rb +1 -1
- data/lib/pg_graph.rb +12 -9
- data/lib/type/type.rb +1 -1
- 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: 9bbbf1239ad74e0ccf7709ce4bd1ccf77d6e319c390836aa749000a0ce3360ef
|
4
|
+
data.tar.gz: 4c433919870bb792e153105cf23ea4f9c969cb8c1251da5671793c5941ebc084
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26f90ddc3c0302bb0584013ab7abeb2236d3d663541a63adc51f9b7d05baa063477efdac183c52ae998fbe14b91da9ebda0f659b8112c35e2fba125254ebbf0b
|
7
|
+
data.tar.gz: a1bd282fd15b758251bab23adf20585b05f2ec58e1ffa39dc91350430bf06f5e8b1c7dda061015376bc42441a9137c52d0d9b30e171b3c2d0a17235c8d1efb9e
|
data/exe/pg_graph
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
#$LOAD_PATH.unshift "/home/clr/prj/shellopts/lib"
|
4
|
+
|
3
5
|
require 'shellopts'
|
4
6
|
require 'pg_graph.rb'
|
5
7
|
require "pg_graph/timer.rb"
|
@@ -32,9 +34,23 @@ SPEC = %(
|
|
32
34
|
Make pg_graph loads its meta data from a marshalled PgMeta object instead
|
33
35
|
of quering the database
|
34
36
|
|
37
|
+
+i,ignore=SCHEMA
|
38
|
+
Exclude objects in the given schema. This option can be repeated
|
39
|
+
|
35
40
|
-r,reflections=EFILE
|
36
41
|
Load reflections from FILE
|
37
42
|
|
43
|
+
-t,reflections-table=TABLE_UID?
|
44
|
+
Read/write reflections in the given table. The table argument can be both a
|
45
|
+
full UID (eg. "my_schema.my_reflections") or just a table name in the public
|
46
|
+
schema. Default is "public.reflections". The table and schema is created
|
47
|
+
if not present.
|
48
|
+
|
49
|
+
If this option is used together with the --reflections option, the
|
50
|
+
reflections are read from th e given file and written back to the database.
|
51
|
+
If both options are missing, pg_graph will look for the default table and
|
52
|
+
load it if present
|
53
|
+
|
38
54
|
-f,format=FORMAT:sql,exec,psql,yaml
|
39
55
|
Input/output format. Can be one of 'sql', 'exec', 'psql', or 'yaml' (default)
|
40
56
|
|
@@ -50,7 +66,7 @@ SPEC = %(
|
|
50
66
|
-k,kind=KIND:meta,type,data
|
51
67
|
Output kind. Can be one of 'meta', 'type' (the default), or 'data'
|
52
68
|
|
53
|
-
|
69
|
+
--time
|
54
70
|
Emit timings for process
|
55
71
|
|
56
72
|
load! -- DATABASE [FILE]
|
@@ -70,24 +86,41 @@ SPEC = %(
|
|
70
86
|
#
|
71
87
|
def load_type(timer, opts, database)
|
72
88
|
tg = timer.group("initialization")
|
73
|
-
|
89
|
+
conn = tg.time("connect") { PgConn.new(database) if !opts.meta? && !opts.marshal? }
|
74
90
|
meta = tg.time("meta") {
|
75
91
|
if opts.meta?
|
76
92
|
PgMeta.load_file(opts.meta)
|
77
93
|
elsif opts.marshal?
|
78
94
|
PgMeta.load_marshal(opts.marshal)
|
79
95
|
else
|
80
|
-
PgMeta.new(
|
96
|
+
PgMeta.new(conn)
|
81
97
|
end
|
82
98
|
}
|
83
99
|
reflector = tg.time("reflector") {
|
84
|
-
|
100
|
+
table, schema = opts.reflections_table&.split(".")&.reverse
|
101
|
+
schema ||= PgGraph::Reflector::REFLECTIONS_SCHEMA
|
102
|
+
table ||= PgGraph::Reflector::REFLECTIONS_TABLE
|
103
|
+
|
104
|
+
if opts.reflections?
|
105
|
+
r = PgGraph::Reflector.load_file(opts.reflections)
|
106
|
+
r.save_table(conn, schema, table) if opts.reflections_table?
|
107
|
+
r
|
108
|
+
else
|
109
|
+
if opts.reflections_table?
|
110
|
+
PgGraph::Reflector.load_table(conn, schema, table)
|
111
|
+
elsif conn.schema.exist_table?(schema, table)
|
112
|
+
PgGraph::Reflector.load_table(conn, schema, table)
|
113
|
+
else
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
end
|
85
117
|
}
|
86
|
-
|
87
|
-
|
118
|
+
|
119
|
+
type = timer.time("type") { PgGraph::Type.new(meta, reflector, ignore: opts.ignore) }
|
120
|
+
[conn, type]
|
88
121
|
end
|
89
122
|
|
90
|
-
opts, args = ShellOpts::ShellOpts.process(SPEC, ARGV
|
123
|
+
opts, args = ShellOpts::ShellOpts.process(SPEC, ARGV)
|
91
124
|
|
92
125
|
timing = opts.time?
|
93
126
|
timer = Timer::Timer.new
|
data/lib/pg_graph/inflector.rb
CHANGED
@@ -86,7 +86,7 @@ module PgGraph
|
|
86
86
|
case name
|
87
87
|
when "character varying", "varchar", "text", "uuid"; String
|
88
88
|
when "smallint", "integer", "int4", "int2"; Integer
|
89
|
-
when "double precision", "real"; Float
|
89
|
+
when "double precision", "real", "float8"; Float
|
90
90
|
when "numeric", "decimal"; BigDecimal
|
91
91
|
when "bool", "boolean"; Boolean
|
92
92
|
when "json"; Hash
|
data/lib/pg_graph/reflector.rb
CHANGED
@@ -26,12 +26,16 @@ module PgGraph
|
|
26
26
|
# matches
|
27
27
|
attr_reader :components
|
28
28
|
|
29
|
+
# True if this is a default reflection
|
30
|
+
attr_reader :default_reflection
|
31
|
+
|
29
32
|
# +this+ and +that+ are template strings, nil, or false
|
30
|
-
def initialize(match, this, that, pluralize = false)
|
33
|
+
def initialize(match, this, that, pluralize = false, default_reflection = false)
|
31
34
|
constrain match, Regexp, String
|
32
35
|
constrain this, String, NilClass
|
33
36
|
constrain that, String, FalseClass, NilClass
|
34
37
|
constrain pluralize, TrueClass, FalseClass, NilClass
|
38
|
+
constrain default_reflection, TrueClass, FalseClass, NilClass
|
35
39
|
@match = match.is_a?(Regexp) ? match.source : match
|
36
40
|
if @match =~ /^\/(.*)\/$/
|
37
41
|
re = $1
|
@@ -45,10 +49,11 @@ module PgGraph
|
|
45
49
|
@this = this
|
46
50
|
@that = that
|
47
51
|
@pluralize = pluralize || pluralize.nil?
|
52
|
+
@default_reflection = default_reflection || false
|
48
53
|
end
|
49
54
|
|
50
55
|
def to_yaml
|
51
|
-
{ match: match, this: this, that: that, pluralize: pluralize }
|
56
|
+
{ match: match, this: this, that: that, pluralize: pluralize, default_reflection: default_reflection }
|
52
57
|
end
|
53
58
|
|
54
59
|
def ==(other)
|
@@ -66,11 +71,13 @@ module PgGraph
|
|
66
71
|
}
|
67
72
|
end
|
68
73
|
|
69
|
-
|
70
|
-
METHODS = %w(match this that pluralize).map(&:to_sym)
|
74
|
+
METHODS = %w(match this that pluralize default_reflection).map(&:to_sym)
|
71
75
|
end
|
72
76
|
|
73
77
|
class Reflector
|
78
|
+
REFLECTIONS_SCHEMA = "public"
|
79
|
+
REFLECTIONS_TABLE = "reflections"
|
80
|
+
|
74
81
|
# Reflections ordered from most-specific to least-specific and newest to oldest
|
75
82
|
def reflections()
|
76
83
|
# assumes @reflection keys are created in descending order
|
@@ -140,6 +147,40 @@ module PgGraph
|
|
140
147
|
load_yaml YAML.load(IO.read(file)), default_reflections: default_reflections
|
141
148
|
end
|
142
149
|
|
150
|
+
def self.load_table(conn, schema = nil, table = nil, default_reflections: Reflector.default_reflections)
|
151
|
+
schema ||= REFLECTIONS_SCHEMA
|
152
|
+
table ||= REFLECTIONS_TABLE
|
153
|
+
if conn.schema.exist?(schema) && conn.schema.exist_table?(schema, table)
|
154
|
+
yaml = conn.structs(%(
|
155
|
+
select match, this, that, pluralize, false as "default_reflection"
|
156
|
+
from #{schema}.#{table}
|
157
|
+
order by ordinal
|
158
|
+
)).map(&:to_h)
|
159
|
+
else
|
160
|
+
yaml = {}
|
161
|
+
end
|
162
|
+
load_yaml yaml, default_reflections: default_reflections
|
163
|
+
end
|
164
|
+
|
165
|
+
def save_table(conn, schema = nil, table = nil)
|
166
|
+
schema ||= REFLECTIONS_SCHEMA
|
167
|
+
table ||= REFLECTIONS_TABLE
|
168
|
+
self.class.ensure_table(conn, schema, table)
|
169
|
+
values = reflections.select { |r| !r.default_reflection }.map.with_index { |reflection, i|
|
170
|
+
values = "(" + Reflection::METHODS.map { |m|
|
171
|
+
v = reflection.send(m)
|
172
|
+
v.nil? ? "null" : "'#{v}'"
|
173
|
+
}.join(", ") + ", #{i})"
|
174
|
+
}.join(",\n")
|
175
|
+
|
176
|
+
conn.exec %(
|
177
|
+
insert into #{schema}.#{table}
|
178
|
+
(match, this, that, pluralize, default_reflection, ordinal)
|
179
|
+
values
|
180
|
+
#{values}
|
181
|
+
)
|
182
|
+
end
|
183
|
+
|
143
184
|
def self.default_reflections
|
144
185
|
@default_reflections ||= begin
|
145
186
|
initializers = [
|
@@ -153,7 +194,9 @@ module PgGraph
|
|
153
194
|
{"match"=>"/(\\w+)_id/", "this"=>"$1", "that"=>"$$"},
|
154
195
|
{"match"=>"/(\\w+)/", "this"=>"$1", "that"=>"$$"}, # Kind fields w/o explicit 'kind'
|
155
196
|
]
|
156
|
-
initializers.map { |initializer|
|
197
|
+
initializers.map { |initializer|
|
198
|
+
Reflection.load_yaml initializer.merge(default_reflection: true)
|
199
|
+
}
|
157
200
|
end
|
158
201
|
end
|
159
202
|
|
@@ -179,6 +222,29 @@ module PgGraph
|
|
179
222
|
end
|
180
223
|
}
|
181
224
|
end
|
225
|
+
|
226
|
+
def self.create_table(conn, schema, table)
|
227
|
+
conn.exec %(
|
228
|
+
create table #{schema}.#{table} (
|
229
|
+
id integer generated by default as identity primary key,
|
230
|
+
match varchar not null,
|
231
|
+
this varchar,
|
232
|
+
that varchar not null,
|
233
|
+
pluralize boolean not null,
|
234
|
+
default_reflection boolean not null,
|
235
|
+
ordinal integer not null -- zero-based
|
236
|
+
)
|
237
|
+
)
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.ensure_table(conn, schema, table)
|
241
|
+
conn.schema.create(schema) if !conn.schema.exist?(schema)
|
242
|
+
if conn.schema.exist_table?(schema, table)
|
243
|
+
conn.exec "truncate #{schema}.#{table}"
|
244
|
+
else
|
245
|
+
create_table(conn, schema, table)
|
246
|
+
end
|
247
|
+
end
|
182
248
|
end
|
183
249
|
end
|
184
250
|
|
data/lib/pg_graph/version.rb
CHANGED
data/lib/pg_graph.rb
CHANGED
@@ -39,26 +39,29 @@ module PgGraph
|
|
39
39
|
# new(meta, reflect = nil)
|
40
40
|
# new(pg_conn, reflect = nil)
|
41
41
|
#
|
42
|
-
# The +
|
43
|
-
# name or nil.
|
44
|
-
#
|
42
|
+
# The +reflections+ argument can be a Reflector object, an yaml array, a
|
43
|
+
# file name, a PgConn object, or nil. If +reflections+ is a PgConn object,
|
44
|
+
# the +schema+ argument should be set to the schema containing the
|
45
|
+
# 'reflections' table. The +ignore+ option is a list of schema names to
|
46
|
+
# exclude from the type system
|
45
47
|
#
|
46
48
|
# Note that together with ::=== and Database#is_a? this makes
|
47
49
|
# Type::Database pretend it is an instance of the Type module
|
48
50
|
#
|
49
|
-
def self.new(arg,
|
51
|
+
def self.new(arg, reflections = nil, schema = nil, ignore: [])
|
50
52
|
constrain arg, PgMeta, PgConn
|
51
|
-
constrain
|
53
|
+
constrain reflections, Reflector, Array, String, PgConn, NilClass
|
52
54
|
meta =
|
53
55
|
case arg
|
54
56
|
when PgMeta; arg
|
55
57
|
when PgConn; PgMeta.new(arg)
|
56
58
|
end
|
57
59
|
reflector =
|
58
|
-
case
|
59
|
-
when Reflector;
|
60
|
-
when Array; Reflector.load_yaml(
|
61
|
-
when String; Reflector.load_file(
|
60
|
+
case reflections
|
61
|
+
when Reflector; reflections
|
62
|
+
when Array; Reflector.load_yaml(reflections)
|
63
|
+
when String; Reflector.load_file(reflections)
|
64
|
+
when PgConn; Reflector.load_table(reflections, schema)
|
62
65
|
when NilClass; Reflector.new
|
63
66
|
end
|
64
67
|
Database.new(meta.name, reflector).read(meta, ignore: ignore)
|
data/lib/type/type.rb
CHANGED
@@ -173,7 +173,7 @@ module PgGraph::Type
|
|
173
173
|
def initialize(
|
174
174
|
schema, name,
|
175
175
|
mm_table: false, nm_table: false, depending_materialized_views: [])
|
176
|
-
PgGraph.inflector.plural?(name) or raise Error, "Table names should be plural: #{name
|
176
|
+
PgGraph.inflector.plural?(name) or raise Error, "Table names should be plural: #{schema.name}.#{name}"
|
177
177
|
super(schema, name)
|
178
178
|
@path = "#{schema.name}.#{name}"
|
179
179
|
@mm_table = mm_table || nm_table
|
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.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: boolean
|