pg_graph 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3a1200417e14fc1e9dae71d0243e78da8a1ee4be0a3929b0a0c118dd46bacd98
4
+ data.tar.gz: 4e8fd62d6ea2846966bb4c7f0f2ec2109eb8ba777d9585616d52794eb7f28e5f
5
+ SHA512:
6
+ metadata.gz: d06d31762eeb3497b7cac9770766635bb2385b5025325037d839145c9d044bb6f477898aaa9c96d5f51183cd389b65d164e515eb90548f505f790b654aaffdb1
7
+ data.tar.gz: fc2fddb0fd4291713d9b646ba369176cc5956bc3e326aff51b36535bb9ec0d564ef0592788e05474e62ac0b69f038b41db652ca5b1717e5caf73628ffb4234c8
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /pkg/
6
+ /spec/reports/
7
+ /tmp/
8
+
9
+ # rspec failure tracking
10
+ .rspec_status
11
+
12
+ # Ignore auto-generated main file
13
+ /main
14
+
15
+ # Ignore Gemfile.lock. See https://stackoverflow.com/questions/4151495/should-gemfile-lock-be-included-in-gitignore
16
+ /Gemfile.lock
17
+
18
+ # Put your personal ignore files in /home/clr/.config/git/ignore
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.7.1
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.1
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in pg_graph.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # PgGraph
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/pg_graph`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'pg_graph'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install pg_graph
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/pg_graph.
36
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/TODO ADDED
@@ -0,0 +1,8 @@
1
+
2
+ o Propagate super table relations to sub-tables
3
+ o Provide a way to exclude certain schemas from the model (eg. prick/postspec/etc.)
4
+ o Move SimpleType to PgCatalog schema
5
+ o Sort type output to make it easier to compare two databases
6
+ o Refactor SQL rendering
7
+
8
+ + Move anchors out of PgGraph
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "pg_graph"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1 @@
1
+ <mxfile host="Electron" modified="2021-06-19T19:00:11.786Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.5.1 Chrome/89.0.4389.82 Electron/12.0.1 Safari/537.36" etag="VEebFTCiVobfmwhjoPcL" version="14.5.1" type="device" pages="4"><diagram name="PgGraph::Type" id="cKRLOOJVSauCXKW0aq4U">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</diagram><diagram name="PgGraph::Data" id="GMbTPo9J8OV5Z1ZZLrwW">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</diagram><diagram id="Xuq1FaBXCnIs1bzDGohJ" name="Example">7Vtbk6I4FP41ProFBBEf29beqZnq2e7tnZqqeYsSMdtAmBhv/es3gaAQEFRwVh2svsDhcHI73/mSk9gBj/7mTwrD+TNxkNcxNGfTAaOOYeimYXTEj+ZsY8nA1mKBS7EjlfaCN/yBpDBRW2IHLTKKjBCP4TArnJIgQFOWkUFKyTqrNiNettQQuigneJtCLy/9jh02l1LdGuwffELYncuibaMfP/BhoixbsphDh6xTIjDugEdKCIuv/M0j8kTnJf3i4tU/0+4rGL++at/+/XCm7z7rxsaeTnll1wSKAtasaTm4K+gtZX91DMvjhQxD0WK2ld1o/VyKZg59SF0cdMADf6qFG/6XC6POEvIuI2H8zEw9Y2jDutDDrnxvyluBaPaxg6aEQoaJ1FkGDqIeDtC+aH7lyv9RBSeJ4NtCWIuFvPkTVZHLQlU2p6rkrPZ6aMbih7Z4qFY1gD4qq8UlyhRwKCzSyBRmrBBlmMPkIR6YUTR0QzlMo7iQIeFaMy9y+hnm3gSGMxIwCXLdkPdP0MeeCA+fkLdCwqroYeZ7Qolf7oAT3TBK3tEj8QiNKgI0DQDLEqZ4CSn5yBzrT71d1UV90UbBdAUg9B1KeXhDxEeMbvl70oo5kMCWkQ1ovfh+nYoTmtSZp0JEX8qgDE3uzvQefvxCIvAENII7QOPYh9i7TjgipWotOI4Hh25px4HDuhQ4zDsAxwuesiVF1wkP7LfccSw8LJU79P8bHtYdwONv4l0pNg7P5FpoKNAwctA4clp1MWj0c9DgPfag5cYOBc6DWHHyO8KVxYwhSFa0dtTHkLJEIyDcpaVM1XmKBnUkPAw5fDUqiyCUzYlLAuiN99L0iPLiUq/G9RMGzhge3jCypFNUvfbjFXZRmT2zdLj13fp4m8wczD8GqY99eFSl0ReCeYN2FkEva9CwSw3G7ZQ20utfxazZP8ls3C05s5ED7nrhfJ+0C8K14o4ULfAHnES3Wj6IFEcaD06QN4TTd5cSHnpTwJ9FHyXWaKWhIxNhDsURYa7o5ZRfd9IZHtmifV7lnBDUL/XJBAIUeZyJVln8HO+IuhKQyGy2QBfxhsH53kDjANq6Q0mIasQblDDXNZTwof8qZ0ncUuGzr9fMZ/oV8Rmo4DMtO9AWqMtnQCFI1XPO5LPeSWYP8BkffrhNqYVCYXG4MT0FBsms7VAtK/T5RVyDZhGit+xaJ5zqWqcMIjdHr3rRNkfLr405xL0RbD4P/5UT7HM9gpUaZQSr3wfBWuXOYqnEVZdg+7bCMYrn9PvnMexAO81uQxRrmkoCBZRTbIX+hSi2KB3fUuzxmCufhd4exfZair2kQ9wbxea3K8Yb6Ici/6+NIO9SuEA5BxIbDEoOPDPScg2bHlcpqgg9PnaciFvXc8zQWwgjHlxTKBwwcjvkSKdN+5qZ3Msq6jWGv3T0lQifDGM6o55k3dMZdUM77CDHZtQ1/CNc23+9M7SdfHn+0u2+8d98BuL2NptecOC2m003vtmkHlMwf+UxhUJo5FMPz7ewdkj7RMNribIIUrmWMMpZUVem/mb5ps4RyTpdCbX9ZpJ14CSzzW0+FXZ+jXTIbzZ3Pwzxm5y6Fzan6NRhO3Nvyh1ud+K+gj9/WJ+B9xK+fV6B6cAesUnBzM9BM7jkc5VkfrWbItHoNM+Fae/K96SsZmhOU84uWHXPWKibXBW8eSzNAfUsyFlnLGonzCr2pCr0ayfMCoHTbkkdG2QPx52b5NzC5tSYgf1unHuGO9wZ5+YnaCHFPhR1VzlXfsXhekn3mg42VmRcLYUmzF7dfSr1BKLZzD6VPTjNblNHQSyl2KqjIOX6l6HddpuqVpy93V2qwua0m1SXdIeboV1+u//adqy+//I7GP8H</diagram><diagram id="KvlQ_p8h7sZ-zoqvewi3" name="Page-3">7Vpdb5swFP01PFYCGwh5zEezSlOnKJ22aS8VhRvi1WDmOGmyXz8DhoCTqmnUNhRFqlp8fH2v7/U5tkNj4FG8+cL9dHHLQqAGMsONgccGQpaNkJH9mOG2QPqeWQARJ6Ey2gF35B8osDRbkRCWDUPBGBUkbYIBSxIIRAPzOWdPTbM5o82oqR/BHnAX+HQf/UlCsVCo5fZ3HTdAooUK7aFe0RH7pbHKZLnwQ/ZUg/C1gUecMVE8xZsR0Kx4ZV2C+2BmAYj7P/8WTjhlP2bTb1eFs8lrhlQpcEjEya6Xv8Rwltxag/vHmQ2/h+vZzVc1xFz7dKXqZSCXyiDDNMtYbFUZ3b+rLM1h7POIJAYeyF4z3cjfEsyLleFXgqVFn13rE7ARVz4lkRoXyCyAN7tDCBj3BWHKZpWEwClJYBdaPkXqbz7BhxKYRrcg/BKWBXjQTSWW6tiC68hJGVOYi6LTyzqfnexetOacUCM2WgMXRHJ4UFRtnNd1qGo4LmIOmbSa05yRcyKXGg/nLBFKgRZS7YkfE5pp9wboGjKvWfIippmRfKxYnTcEZ48wYpTxfCLYNDF23cyVjFDDx/a1NXGqqWfzhY0muBfYalUSknsPsBgE38pxykvPVtRU245dtp9qIjYVtqjp11WYr/aNqHK904Z8UPJ4hVSsTkgl3+WzgXjwfZvCRTWdVg02z60a1DXVjP3LWdMx1TjYaZlqcAdUM2Gbi046pRNXO10s99w6sTugkylbimUKwUUsnRIL6jstE4vTBbFEdyRO6eVzS7fEot/AHO/cYnEPiEVbNkjCQfaCUrYSJtnbKHRhDeHey8lj6iTDsBUP4GUxC8lLEC+dkPt1r9XVOVDWEuNApVDXzRwO1VpFmDIis6uWFePmhQHZ2nIVaapR9XeXuiNPu3n0NUdFHfYc5UtfpX06G7yOsME0zsiGnttcRBefyAbPajqqdosPYkO/5Wwwj2TDM3vyB7Gh/1ZssM/LhpKMraUD/hR0QNpR0TuRDr2e5gh9MB0O/Z+gTXRAR9IBn5MOSDvwbV3UR98ctCuIrW8z702HQ6/yPiMdWnWRdKxT6aDzSv8A8d50OPTGqk10sD/l7nDqYbG3O7zZYSGbu2+GFOa779fg6/8=</diagram></mxfile>
data/exe/pg_graph ADDED
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'shellopts'
4
+ require 'pg_graph.rb'
5
+ require "pg_graph/timer.rb"
6
+
7
+ include ShellOpts
8
+
9
+ PROGRAM = File.basename($PROGRAM_NAME)
10
+ SPEC = %(
11
+ -m,meta=EFILE @ Load meta data from YAML file
12
+ Make pg_graph loads its meta data in YAML format from FILE instead of
13
+ querying the database
14
+
15
+ -M,marshal=EFILE @ Load meta data from marshalled file
16
+ Make pg_graph loads its meta data from a marshalled PgMeta object instead
17
+ of quering the database
18
+
19
+ -r,reflections=EFILE
20
+ Load reflections from FILE
21
+
22
+ -f,format=FORMAT:sql,exec,psql,yaml
23
+ Input/output format. Can be one of 'sql', 'exec', 'psql', or 'yaml' (default)
24
+
25
+ -k,kind=KIND:meta,type,data
26
+ Output kind. Can be one of 'meta', 'type' (the default), or 'data'
27
+
28
+ -t,time
29
+ Emit timings for process
30
+
31
+ load! -- [FILE] DATABASE
32
+ Loads data into the database. The file format is determined by the file's
33
+ extension but can also be set explicitly using the --format option.
34
+
35
+ dump! -- DATABASE
36
+ Dumps data on standard output. Default is to dump the type system in yaml
37
+ format but this can be explicitly set using the --kind and --format options
38
+
39
+ clean! -- DATABASE
40
+ Cleans the database by emptying all tables
41
+ )
42
+
43
+ # Returns a connection/type tuple
44
+ #
45
+ def load_type(timer, opts, database)
46
+ tg = timer.group("initialization")
47
+ connection = tg.time("connect") { PgConn.new(database) if !opts.meta? && !opts.marshal? }
48
+ meta = tg.time("meta") {
49
+ if opts.meta?
50
+ PgMeta.load_file(opts.meta)
51
+ elsif opts.marshal?
52
+ PgMeta.load_marshal(opts.marshal)
53
+ else
54
+ PgMeta.new(connection)
55
+ end
56
+ }
57
+ reflector = tg.time("reflector") {
58
+ opts.reflections? ? PgGraph::Reflector.load_file(opts.reflections) : nil
59
+ }
60
+ type = timer.time("type") { PgGraph::Type.new(meta, reflector) }
61
+ [connection, type]
62
+ end
63
+
64
+ opts, args = ShellOpts::ShellOpts.process(SPEC, ARGV)
65
+
66
+ timing = opts.time?
67
+ timer = Timer::Timer.new
68
+
69
+ # Process options
70
+ meta = opts.meta
71
+ reflections = opts.reflections
72
+ kind = opts.kind || "type"
73
+ format = opts.format || "yaml"
74
+
75
+ case opts.subcommand || :dump!
76
+ when :load!
77
+ database = args.expect(-1)
78
+ file = args.expect(0..1) || "/dev/stdin"
79
+
80
+ if opts.format?
81
+ format = opts.format
82
+ else
83
+ format =
84
+ case File.extname(file)
85
+ when ".sql"; "sql"
86
+ when ".yaml", ".yml"; "yaml"
87
+ else
88
+ "yaml"
89
+ end
90
+ end
91
+
92
+ case format
93
+ when "sql", "exec";
94
+ connection = timer.time("connect") { PgConn.new(database) }
95
+ timer.time("load file") {
96
+ connection.exec(IO.read(file))
97
+ }
98
+ when "psql"
99
+ timer.time("psql") {
100
+ system "psql -d #{database} < #{file} >/dev/null"
101
+ }
102
+ when "yaml"
103
+ connection, type = load_type(timer, opts, database)
104
+ tg = timer.group("read data")
105
+ data = tg.time("data") { PgGraph::Data.new(type, YAML.load(IO.read(file))) }
106
+ tg = timer.group("write data")
107
+ for label, sql in PgGraph::Data::SqlRender.new(data, :exec).to_h
108
+ tg.time(label) { connection.exec(sql.join) }
109
+ end
110
+ end
111
+
112
+ when :dump!
113
+ database = args.expect(1)
114
+
115
+ case kind
116
+ when "meta"
117
+ connection = timer.time("connect") { PgConn.new(database) if !opts.meta? }
118
+ meta = timer.time("meta") { opts.meta? ? PgMeta.load_file(opts.meta) : PgMeta.new(connection) }
119
+ meta.dump
120
+ when "type"
121
+ connection, type = load_type(timer, opts, database)
122
+ type.dump
123
+ when "data"
124
+ connection, type = load_type(timer, opts, database)
125
+ data = timer.time("instantiate") { type.instantiate(connection) }
126
+ timer.time("dump") {
127
+ case format
128
+ when "sql"; puts data.to_sql
129
+ when "exec"; puts data.to_exec_sql
130
+ when "psql"; puts data.to_psql_sql
131
+ when "yaml"; puts data.to_yaml.to_yaml
132
+ end
133
+ }
134
+ end
135
+
136
+ when :clean!
137
+ database = args.expect(1)
138
+
139
+ connection, type = load_type(timer, opts, database)
140
+ tg = timer.group("data")
141
+ data = tg.time("data") { type.instantiate }
142
+
143
+ tg = timer.group("clean data")
144
+ for label, sql in PgGraph::Data::SqlRender.new(data, :exec).to_h
145
+ tg.time(label) { connection.exec(sql.join) }
146
+ end
147
+ else
148
+ raise ArgumentError, "Case not matched"
149
+ end
150
+
151
+ timer.dump($stderr) if timing
152
+
@@ -0,0 +1,98 @@
1
+ module PgGraph::Data
2
+ class Association
3
+ attr_reader :this_table
4
+ attr_reader :this_field
5
+ attr_reader :that_table
6
+ attr_reader :that_field
7
+
8
+ # Dimension of the association
9
+ attr_reader :dimension
10
+
11
+ def initialize(dimension, this_table, that_table, this_field, that_field)
12
+ Dimension.validate(dimension, min: 1)
13
+ constrain this_table, Table
14
+ constrain that_table, Table
15
+ constrain this_field, String, Symbol
16
+ constrain that_field, String, Symbol
17
+ @dimension = dimension
18
+ @this_table, @this_field = this_table, this_field
19
+ @that_table, @that_field = that_table, that_field
20
+ end
21
+
22
+ # Query the association and return a query object (Record, Query, or
23
+ # QueryWithDuplicates)
24
+ def query(field) raise NotThis end
25
+
26
+ # Get object(s). Either a single record or a list of (possible duplicate)
27
+ # records
28
+ def get(record) dimension == 1 ? get_record(record) : get_records(record) end
29
+
30
+ def get_record(this_record)
31
+ if that_field == :id
32
+ that_table[this_record[this_field].value]
33
+ else
34
+ that_table.records.find { |that_record|
35
+ that_record[that_field].value == this_record[this_field].value
36
+ }
37
+ end
38
+ end
39
+
40
+ def get_records(this_record)
41
+ that_table.records.find_all { |that_record|
42
+ that_record[that_field].value == this_record[this_field].value
43
+ }
44
+ end
45
+ end
46
+
47
+ class KindAssociation < Association
48
+ end
49
+
50
+ class LinkAssociation < Association
51
+ # From this table to the link table. TableAssociation object
52
+ attr_reader :this_association
53
+
54
+ # From the link table to 'that' table. RecordAssociation object
55
+ attr_reader :that_association
56
+
57
+ # The link table in the N:M relation
58
+ def link_table() this_association.that_table end
59
+
60
+ # The field in the link table that links to this record
61
+ def this_link_field() this_association.that_field end
62
+
63
+ # The field in the link table that links to that record
64
+ def that_link_field() that_association.this_field end
65
+
66
+ def initialize(
67
+ dimension,
68
+ this_table, that_table, link_table,
69
+ this_field, this_link_field, that_link_field, that_field)
70
+ super(dimension, this_table, that_table, this_field, that_field)
71
+ @this_association = Association.new(2, this_table, link_table, this_field, this_link_field)
72
+ @that_association = Association.new(1, link_table, that_table, that_link_field, that_field)
73
+ end
74
+
75
+ # Note that records are not unique for MmTableAssociation but for
76
+ # NmTableAssociation objects
77
+ def get_records(record)
78
+ @this_association.get(record).map { |link_record| @that_association.get(link_record) }
79
+ end
80
+ end
81
+ end
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+