pg_graph 0.1.1 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|