pg_graph 0.1.0

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 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
+