pg_graph 0.1.1 → 0.1.4
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/Gemfile +0 -7
- data/exe/pg_graph +50 -14
- data/lib/data/data.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
- data/pg_graph.gemspec +4 -0
- metadata +44 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea523768bdb76ecb1e4d8a8cee3d1b4afbad3e5735964acf63f78d5152050cf5
|
4
|
+
data.tar.gz: a29f1abbbdb5b674090a503c9db9ab0357140035b2c5af62a07352d38d5f3009
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad4d4f581462c3b982d7e7504a6277e7585e1d422974a6058ca9ba54c4e30ed48ba5ba38e88504d449caa8690c7664a46366187e2ceab7e19a2f8f26abb944ac
|
7
|
+
data.tar.gz: fff6a163e030d2dfd1187c07e6e69d0da9dbef18b4c0ef2fda393dfe7f9725e61c21f47febed69199b553b17f0285f16c30951e623e0143f0dd37d302228fd8b
|
data/Gemfile
CHANGED
@@ -3,10 +3,3 @@ source "https://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in pg_graph.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem "rake", "~> 12.0"
|
7
|
-
gem "rspec", "~> 3.0"
|
8
|
-
|
9
|
-
gem 'shellopts', :github => 'clrgit/shellopts', branch: "master"
|
10
|
-
gem 'pg_conn', :github => 'clrgit/pg_conn', branch: "master"
|
11
|
-
gem 'pg_meta', :github => 'clrgit/pg_meta', branch: "master"
|
12
|
-
|
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"
|
@@ -12,14 +14,17 @@ SPEC = %(
|
|
12
14
|
pg_graph is a utility that uses the PgGraph module to load, dump, or clean a
|
13
15
|
database. It uses a variety of formats that can be executed by psql(1)
|
14
16
|
('psql') or by the Postgres library exec() call ('exec', 'sql'). It can also
|
15
|
-
read and write Yaml data ('yaml')
|
16
|
-
|
17
|
+
read and write Yaml data ('yaml') that is useful for exchanging data with
|
18
|
+
other programs
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
except in the special case when the data
|
21
|
-
|
22
|
-
|
20
|
+
Note that when you're loading or dumping data in one of the SQL formats,
|
21
|
+
you're almost always better off using postgres' own tools
|
22
|
+
(pg_dump/pg_restore/pg_sql), except in the special case when the data
|
23
|
+
contains circular foreign-key constraints and you don't have superuser
|
24
|
+
privileges
|
25
|
+
|
26
|
+
The dump command can also write the type of the database in yaml format. This
|
27
|
+
is the default
|
23
28
|
|
24
29
|
-m,meta=EFILE @ Load meta data from YAML file
|
25
30
|
Make pg_graph loads its meta data in YAML format from FILE instead of
|
@@ -29,9 +34,23 @@ SPEC = %(
|
|
29
34
|
Make pg_graph loads its meta data from a marshalled PgMeta object instead
|
30
35
|
of quering the database
|
31
36
|
|
37
|
+
+i,ignore=SCHEMA
|
38
|
+
Exclude objects in the given schema. This option can be repeated
|
39
|
+
|
32
40
|
-r,reflections=EFILE
|
33
41
|
Load reflections from FILE
|
34
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
|
+
|
35
54
|
-f,format=FORMAT:sql,exec,psql,yaml
|
36
55
|
Input/output format. Can be one of 'sql', 'exec', 'psql', or 'yaml' (default)
|
37
56
|
|
@@ -47,7 +66,7 @@ SPEC = %(
|
|
47
66
|
-k,kind=KIND:meta,type,data
|
48
67
|
Output kind. Can be one of 'meta', 'type' (the default), or 'data'
|
49
68
|
|
50
|
-
|
69
|
+
--time
|
51
70
|
Emit timings for process
|
52
71
|
|
53
72
|
load! -- DATABASE [FILE]
|
@@ -67,24 +86,41 @@ SPEC = %(
|
|
67
86
|
#
|
68
87
|
def load_type(timer, opts, database)
|
69
88
|
tg = timer.group("initialization")
|
70
|
-
|
89
|
+
conn = tg.time("connect") { PgConn.new(database) if !opts.meta? && !opts.marshal? }
|
71
90
|
meta = tg.time("meta") {
|
72
91
|
if opts.meta?
|
73
92
|
PgMeta.load_file(opts.meta)
|
74
93
|
elsif opts.marshal?
|
75
94
|
PgMeta.load_marshal(opts.marshal)
|
76
95
|
else
|
77
|
-
PgMeta.new(
|
96
|
+
PgMeta.new(conn)
|
78
97
|
end
|
79
98
|
}
|
80
99
|
reflector = tg.time("reflector") {
|
81
|
-
|
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
|
82
117
|
}
|
83
|
-
|
84
|
-
|
118
|
+
|
119
|
+
type = timer.time("type") { PgGraph::Type.new(meta, reflector, ignore: opts.ignore) }
|
120
|
+
[conn, type]
|
85
121
|
end
|
86
122
|
|
87
|
-
opts, args = ShellOpts::ShellOpts.process(SPEC, ARGV
|
123
|
+
opts, args = ShellOpts::ShellOpts.process(SPEC, ARGV)
|
88
124
|
|
89
125
|
timing = opts.time?
|
90
126
|
timer = Timer::Timer.new
|
data/lib/data/data.rb
CHANGED
@@ -160,7 +160,7 @@ module PgGraph::Data
|
|
160
160
|
def write(connection, ids: {}, delete: :all)
|
161
161
|
constrain connection, PgConn
|
162
162
|
constrain ids, String => Integer
|
163
|
-
connection.exec(to_exec_sql(ids: ids, delete:
|
163
|
+
connection.exec(to_exec_sql(ids: ids, delete: delete))
|
164
164
|
self
|
165
165
|
end
|
166
166
|
|
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
|
data/pg_graph.gemspec
CHANGED
@@ -35,6 +35,10 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_dependency "pg_conn"
|
36
36
|
spec.add_dependency "pg_meta"
|
37
37
|
|
38
|
+
spec.add_development_dependency "rake"
|
39
|
+
spec.add_development_dependency "rspec"
|
40
|
+
spec.add_development_dependency "simplecov"
|
41
|
+
|
38
42
|
# Also un-comment in spec/spec_helper to use simplecov
|
39
43
|
# spec.add_development_dependency "simplecov"
|
40
44
|
end
|
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.4
|
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-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: boolean
|
@@ -136,6 +136,48 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rake
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rspec
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: simplecov
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
139
181
|
description: dwpg_graph gem
|
140
182
|
email:
|
141
183
|
- claus.l.rasmussen@gmail.com
|