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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28f5cb17edb384621612f29426084e14f15db45572e5ba80482776b4ca04b3ce
4
- data.tar.gz: e2b1cf4db09e79d2a2d726dbd4ecdaa22fc82ddc4fbd94e9b10cb15220712096
3
+ metadata.gz: ea523768bdb76ecb1e4d8a8cee3d1b4afbad3e5735964acf63f78d5152050cf5
4
+ data.tar.gz: a29f1abbbdb5b674090a503c9db9ab0357140035b2c5af62a07352d38d5f3009
5
5
  SHA512:
6
- metadata.gz: 27ab8c10fbf8717e6086983cab0ce5cc32908c41c4d66402031a5bbac12b9ea623f095a4d9a9b6ac02018b34eac6dc2718be50c7c6449698008ea2b348baa4be
7
- data.tar.gz: 8eca990262bb1e8fde6e5dcab49a40a2677ce368528d9485e4742c924cab1225994ac68d9e8f507f18e671ca413998cb73819b2a671cc2476dd850444754979e
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'). The dump command can also write the meta
16
- data and type of the database in yaml format which is useful for debugging.
17
+ read and write Yaml data ('yaml') that is useful for exchanging data with
18
+ other programs
17
19
 
18
- The default is to dump the type in yaml format, this is also the typical use
19
- of pg_graph because dump of data is better done using 'pg_dump -a <database>'
20
- except in the special case when the data contains circular foreign-key
21
- constraints and the load command is run by an ordinary user. The load command
22
- is useful when you want to read Yaml data from other programs into the database
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
- -t,time
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
- connection = tg.time("connect") { PgConn.new(database) if !opts.meta? && !opts.marshal? }
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(connection)
96
+ PgMeta.new(conn)
78
97
  end
79
98
  }
80
99
  reflector = tg.time("reflector") {
81
- opts.reflections? ? PgGraph::Reflector.load_file(opts.reflections) : nil
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
- type = timer.time("type") { PgGraph::Type.new(meta, reflector) }
84
- [connection, type]
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, :version => PgGraph::VERSION)
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: :all))
163
+ connection.exec(to_exec_sql(ids: ids, delete: delete))
164
164
  self
165
165
  end
166
166
 
@@ -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
- private
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| Reflection.load_yaml(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
 
@@ -1,3 +1,3 @@
1
1
  module PgGraph
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.4"
3
3
  end
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 +reflect+ argument can be a Reflector object, an yaml array, a file
43
- # name or nil. The +ignore+ option is a list of schema names to exclude
44
- # from the type system
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, reflect = nil, ignore: [])
51
+ def self.new(arg, reflections = nil, schema = nil, ignore: [])
50
52
  constrain arg, PgMeta, PgConn
51
- constrain reflect, Reflector, Array, String, NilClass
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 reflect
59
- when Reflector; reflect
60
- when Array; Reflector.load_yaml(reflect)
61
- when String; Reflector.load_file(reflect)
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.inspect}"
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.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-03-06 00:00:00.000000000 Z
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