table_saw 0.3.0 → 0.4.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 +4 -4
- data/.rubocop.yml +3 -0
- data/Gemfile.lock +6 -1
- data/exe/table-saw +1 -3
- data/lib/table_saw/create_dump_file.rb +16 -6
- data/lib/table_saw/dependency_graph/add_directive.rb +26 -0
- data/lib/table_saw/dependency_graph/belongs_to_directives.rb +41 -0
- data/lib/table_saw/dependency_graph/build.rb +51 -0
- data/lib/table_saw/dependency_graph/context.rb +42 -0
- data/lib/table_saw/dependency_graph/dump_table.rb +40 -0
- data/lib/table_saw/dependency_graph/has_many_directives.rb +45 -0
- data/lib/table_saw/dependency_graph.rb +8 -0
- data/lib/table_saw/manifest.rb +5 -1
- data/lib/table_saw/queries/foreign_key_relationships.rb +0 -2
- data/lib/table_saw/queries/materialized_views.rb +0 -2
- data/lib/table_saw/queries/table_columns.rb +0 -2
- data/lib/table_saw/queries.rb +6 -0
- data/lib/table_saw/version.rb +1 -1
- data/lib/table_saw.rb +4 -1
- data/table_saw.gemspec +1 -0
- metadata +24 -3
- data/lib/table_saw/build_dependency_graph.rb +0 -97
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1339fbe2ad8b61d13d84595da082e4bd8886f9ecb56e1c8ce55ba9b5d9d33304
|
4
|
+
data.tar.gz: 79e448b1ee7d8f77a019b491ed5cbe11e4b5ca353721643211543813a779b856
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49bf13e6be2584987b29755ca760fced988ff01f7f8ad362a2cb35122f83da8de7b1de37c0f02d32bee9dee733b0d9c517d515dc5134cb00a4e08c26f57af9c1
|
7
|
+
data.tar.gz: 290706ba80434334c9d4af235e84972018bad3d2ef009eb85ee288ce6e7739fb669e1ba428e8060e6c1509910a0cdb0bffe05f26fdeee562772b69d41c1fe687
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
table_saw (0.
|
4
|
+
table_saw (0.4.0)
|
5
5
|
connection_pool
|
6
6
|
pg
|
7
7
|
thor
|
@@ -36,6 +36,7 @@ GEM
|
|
36
36
|
arel (9.0.0)
|
37
37
|
ast (2.4.0)
|
38
38
|
builder (3.2.3)
|
39
|
+
coderay (1.1.2)
|
39
40
|
combustion (1.1.0)
|
40
41
|
activesupport (>= 3.0.0)
|
41
42
|
railties (>= 3.0.0)
|
@@ -63,6 +64,9 @@ GEM
|
|
63
64
|
parser (2.6.3.0)
|
64
65
|
ast (~> 2.4.0)
|
65
66
|
pg (1.1.4)
|
67
|
+
pry (0.12.2)
|
68
|
+
coderay (~> 1.1.0)
|
69
|
+
method_source (~> 0.9.0)
|
66
70
|
rack (2.0.7)
|
67
71
|
rack-test (1.1.0)
|
68
72
|
rack (>= 1.0, < 3)
|
@@ -124,6 +128,7 @@ DEPENDENCIES
|
|
124
128
|
bundler (~> 2.0)
|
125
129
|
combustion (~> 1.1)
|
126
130
|
database_cleaner (~> 1.7)
|
131
|
+
pry
|
127
132
|
rake (~> 10.0)
|
128
133
|
rspec (~> 3.0)
|
129
134
|
rubocop-rspec (~> 1.33)
|
data/exe/table-saw
CHANGED
@@ -5,9 +5,7 @@ lib = File.expand_path('../lib', __dir__)
|
|
5
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
6
|
|
7
7
|
require 'table_saw'
|
8
|
-
require 'table_saw/build_dependency_graph'
|
9
8
|
require 'table_saw/create_dump_file'
|
10
|
-
require 'table_saw/manifest'
|
11
9
|
require 'thor'
|
12
10
|
|
13
11
|
class CLI < Thor
|
@@ -27,7 +25,7 @@ class CLI < Thor
|
|
27
25
|
method_option :output, aliases: '-o', default: 'output.dump'
|
28
26
|
def dump
|
29
27
|
TableSaw.configure(options.to_hash)
|
30
|
-
records = TableSaw::
|
28
|
+
records = TableSaw::DependencyGraph::Build.new(TableSaw::Manifest.instance).call
|
31
29
|
TableSaw::CreateDumpFile.new(records, options[:output]).call
|
32
30
|
end
|
33
31
|
end
|
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'table_saw/queries/table_columns'
|
4
|
-
require 'table_saw/queries/materialized_views'
|
5
|
-
|
6
3
|
module TableSaw
|
7
4
|
class CreateDumpFile
|
8
5
|
attr_reader :records, :file
|
@@ -28,7 +25,7 @@ module TableSaw
|
|
28
25
|
SET search_path = public, pg_catalog;
|
29
26
|
SQL
|
30
27
|
|
31
|
-
records.each do |name,
|
28
|
+
records.each do |name, table|
|
32
29
|
write_to_file <<~COMMENT
|
33
30
|
--
|
34
31
|
-- Data for Name: #{name}; Type: TABLE DATA
|
@@ -41,7 +38,7 @@ module TableSaw
|
|
41
38
|
SQL
|
42
39
|
|
43
40
|
TableSaw::Connection.with do |conn|
|
44
|
-
conn.copy_data "COPY (
|
41
|
+
conn.copy_data "COPY (#{table.copy_statement}) TO STDOUT" do
|
45
42
|
while (row = conn.get_copy_data)
|
46
43
|
write_to_file row
|
47
44
|
end
|
@@ -53,6 +50,7 @@ module TableSaw
|
|
53
50
|
end
|
54
51
|
|
55
52
|
refresh_materialized_views
|
53
|
+
restart_sequences
|
56
54
|
|
57
55
|
write_to_file 'COMMIT;'
|
58
56
|
end
|
@@ -62,8 +60,20 @@ module TableSaw
|
|
62
60
|
|
63
61
|
def refresh_materialized_views
|
64
62
|
TableSaw::Queries::MaterializedViews.new.call.each do |view|
|
65
|
-
write_to_file "
|
63
|
+
write_to_file "refresh materialized view #{view};"
|
64
|
+
end
|
65
|
+
|
66
|
+
write_to_file "\n"
|
67
|
+
end
|
68
|
+
|
69
|
+
def restart_sequences
|
70
|
+
records.each_key do |table|
|
71
|
+
write_to_file <<~SQL
|
72
|
+
select setval(pg_get_serial_sequence('#{table}', 'id'), (select max(id) from #{table}), true);
|
73
|
+
SQL
|
66
74
|
end
|
75
|
+
|
76
|
+
write_to_file "\n"
|
67
77
|
end
|
68
78
|
|
69
79
|
def write_to_file(data)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSaw
|
4
|
+
module DependencyGraph
|
5
|
+
class AddDirective
|
6
|
+
attr_reader :table_name, :partial
|
7
|
+
attr_accessor :ids
|
8
|
+
|
9
|
+
def initialize(table_name, ids: [], partial: true)
|
10
|
+
@table_name = table_name
|
11
|
+
@ids = ids
|
12
|
+
@partial = partial
|
13
|
+
end
|
14
|
+
|
15
|
+
alias partial? partial
|
16
|
+
|
17
|
+
def selectable?
|
18
|
+
partial? && Array(ids).size.positive?
|
19
|
+
end
|
20
|
+
|
21
|
+
def queryable?
|
22
|
+
!partial || selectable?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSaw
|
4
|
+
module DependencyGraph
|
5
|
+
class BelongsToDirectives
|
6
|
+
attr_reader :context, :directive
|
7
|
+
|
8
|
+
def initialize(context, directive)
|
9
|
+
@context = context
|
10
|
+
@directive = directive
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
associations.map do |from_column, to_table|
|
15
|
+
TableSaw::DependencyGraph::AddDirective.new(to_table, ids: ids[from_column].to_a, partial: directive.partial?)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def associations
|
22
|
+
context.belongs_to.fetch(directive.table_name, {})
|
23
|
+
end
|
24
|
+
|
25
|
+
def ids
|
26
|
+
@ids ||= query_result.each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |row, memo|
|
27
|
+
associations.each_key { |key| memo[key].add row[key] unless row[key].nil? }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def query_result
|
32
|
+
return [] unless directive.selectable?
|
33
|
+
|
34
|
+
context.perform_query(
|
35
|
+
format('select %{columns} from %{table_name} where id in (%{ids})',
|
36
|
+
columns: associations.keys.join(','), table_name: directive.table_name, ids: directive.ids.join(','))
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSaw
|
4
|
+
module DependencyGraph
|
5
|
+
class Build
|
6
|
+
attr_reader :manifest, :records
|
7
|
+
|
8
|
+
def initialize(manifest)
|
9
|
+
@manifest = manifest
|
10
|
+
@records = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
manifest.tables.values.sort_by { |t| t.partial? ? 1 : 0 }.each do |table|
|
15
|
+
add TableSaw::DependencyGraph::AddDirective.new(table.name, ids: select_ids(table), partial: table.partial?)
|
16
|
+
end
|
17
|
+
|
18
|
+
records
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def add(directive)
|
24
|
+
return [] unless directive.queryable?
|
25
|
+
|
26
|
+
directives(directive).select(&:queryable?).each(&method(:add))
|
27
|
+
end
|
28
|
+
|
29
|
+
def directives(dir)
|
30
|
+
record = records[dir.table_name]
|
31
|
+
|
32
|
+
if record
|
33
|
+
dir.partial? ? record.fetch_associations(dir) : []
|
34
|
+
else
|
35
|
+
TableSaw::DependencyGraph::DumpTable.new(context: context, name: dir.table_name, partial: dir.partial?)
|
36
|
+
.tap { |table| records[dir.table_name] = table }.fetch_associations(dir)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def context
|
41
|
+
@context ||= TableSaw::DependencyGraph::Context.new(manifest)
|
42
|
+
end
|
43
|
+
|
44
|
+
def select_ids(table)
|
45
|
+
return [] unless table.partial?
|
46
|
+
|
47
|
+
context.perform_query(table.query).map { |row| row['id'] }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSaw
|
4
|
+
module DependencyGraph
|
5
|
+
class Context
|
6
|
+
attr_reader :manifest
|
7
|
+
|
8
|
+
def initialize(manifest)
|
9
|
+
@manifest = manifest
|
10
|
+
end
|
11
|
+
|
12
|
+
def belongs_to
|
13
|
+
foreign_key_relationships.belongs_to
|
14
|
+
end
|
15
|
+
|
16
|
+
# rubocop:disable Naming/PredicateName
|
17
|
+
def has_many
|
18
|
+
foreign_key_relationships.has_many
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_many_mapping
|
22
|
+
@has_many_mapping ||= manifest.tables.transform_values(&:has_many)
|
23
|
+
end
|
24
|
+
|
25
|
+
# rubocop:enable Naming/PredicateName
|
26
|
+
|
27
|
+
def foreign_key_relationships
|
28
|
+
@foreign_key_relationships ||= TableSaw::Queries::ForeignKeyRelationships.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def tables_with_no_ids
|
32
|
+
@tables_with_no_ids ||= TableSaw::Queries::NoIdTables.new.call
|
33
|
+
end
|
34
|
+
|
35
|
+
def perform_query(sql)
|
36
|
+
TableSaw::Connection.with do |conn|
|
37
|
+
conn.exec(sql)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSaw
|
4
|
+
module DependencyGraph
|
5
|
+
class DumpTable
|
6
|
+
attr_reader :context, :name, :partial, :ids
|
7
|
+
|
8
|
+
def initialize(context:, name:, partial: true)
|
9
|
+
@context = context
|
10
|
+
@name = name
|
11
|
+
@partial = partial
|
12
|
+
@ids = Set.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def copy_statement
|
16
|
+
if partial
|
17
|
+
"select * from #{name} where id in (#{ids.to_a.join(',')})"
|
18
|
+
else
|
19
|
+
"select * from #{name}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch_associations(directive)
|
24
|
+
directive.ids = directive.ids - ids.to_a
|
25
|
+
ids.merge(directive.ids)
|
26
|
+
fetch_belongs_to(directive) + fetch_has_many(directive)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def fetch_belongs_to(directive)
|
32
|
+
TableSaw::DependencyGraph::BelongsToDirectives.new(context, directive).call
|
33
|
+
end
|
34
|
+
|
35
|
+
def fetch_has_many(directive)
|
36
|
+
TableSaw::DependencyGraph::HasManyDirectives.new(context, directive).call
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSaw
|
4
|
+
module DependencyGraph
|
5
|
+
class HasManyDirectives
|
6
|
+
attr_reader :context, :directive
|
7
|
+
|
8
|
+
def initialize(context, directive)
|
9
|
+
@context = context
|
10
|
+
@directive = directive
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
valid_associations.map do |table, column|
|
15
|
+
TableSaw::DependencyGraph::AddDirective.new(
|
16
|
+
table, ids: query_result(table, column).map { |r| r['id'] }, partial: directive.partial?
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def associations
|
24
|
+
context.has_many.fetch(directive.table_name, [])
|
25
|
+
end
|
26
|
+
|
27
|
+
def valid_associations
|
28
|
+
associations.select do |table, _column|
|
29
|
+
next false if directive.partial? && context.tables_with_no_ids.include?(table)
|
30
|
+
|
31
|
+
context.has_many_mapping.fetch(directive.table_name, []).include?(table)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def query_result(table, column)
|
36
|
+
return [] unless directive.selectable?
|
37
|
+
|
38
|
+
context.perform_query(
|
39
|
+
format('select id from %{table} where %{column} in (%{ids})',
|
40
|
+
table: table, column: column, ids: directive.ids.join(','))
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'table_saw/dependency_graph/add_directive'
|
4
|
+
require 'table_saw/dependency_graph/belongs_to_directives'
|
5
|
+
require 'table_saw/dependency_graph/build'
|
6
|
+
require 'table_saw/dependency_graph/context'
|
7
|
+
require 'table_saw/dependency_graph/dump_table'
|
8
|
+
require 'table_saw/dependency_graph/has_many_directives'
|
data/lib/table_saw/manifest.rb
CHANGED
@@ -31,6 +31,10 @@ module TableSaw
|
|
31
31
|
config.fetch('has_many', [])
|
32
32
|
end
|
33
33
|
# rubocop:enable Naming/PredicateName
|
34
|
+
|
35
|
+
def partial?
|
36
|
+
config.key?('query')
|
37
|
+
end
|
34
38
|
end
|
35
39
|
|
36
40
|
def self.instance
|
@@ -46,7 +50,7 @@ module TableSaw
|
|
46
50
|
end
|
47
51
|
|
48
52
|
def variables
|
49
|
-
config
|
53
|
+
config.fetch('variables', {})
|
50
54
|
end
|
51
55
|
|
52
56
|
def tables
|
data/lib/table_saw/version.rb
CHANGED
data/lib/table_saw.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'table_saw/version'
|
4
3
|
require 'table_saw/configuration'
|
4
|
+
require 'table_saw/connection'
|
5
|
+
require 'table_saw/dependency_graph'
|
6
|
+
require 'table_saw/manifest'
|
7
|
+
require 'table_saw/queries'
|
5
8
|
|
6
9
|
module TableSaw
|
7
10
|
def self.configuration
|
data/table_saw.gemspec
CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
32
32
|
spec.add_development_dependency 'combustion', '~> 1.1'
|
33
33
|
spec.add_development_dependency 'database_cleaner', '~> 1.7'
|
34
|
+
spec.add_development_dependency 'pry'
|
34
35
|
spec.add_development_dependency 'rake', '~> 10.0'
|
35
36
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
36
37
|
spec.add_development_dependency 'rubocop-rspec', '~> 1.33'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: table_saw
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hamed Asghari
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: connection_pool
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '1.7'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rake
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -202,11 +216,18 @@ files:
|
|
202
216
|
- bin/setup
|
203
217
|
- exe/table-saw
|
204
218
|
- lib/table_saw.rb
|
205
|
-
- lib/table_saw/build_dependency_graph.rb
|
206
219
|
- lib/table_saw/configuration.rb
|
207
220
|
- lib/table_saw/connection.rb
|
208
221
|
- lib/table_saw/create_dump_file.rb
|
222
|
+
- lib/table_saw/dependency_graph.rb
|
223
|
+
- lib/table_saw/dependency_graph/add_directive.rb
|
224
|
+
- lib/table_saw/dependency_graph/belongs_to_directives.rb
|
225
|
+
- lib/table_saw/dependency_graph/build.rb
|
226
|
+
- lib/table_saw/dependency_graph/context.rb
|
227
|
+
- lib/table_saw/dependency_graph/dump_table.rb
|
228
|
+
- lib/table_saw/dependency_graph/has_many_directives.rb
|
209
229
|
- lib/table_saw/manifest.rb
|
230
|
+
- lib/table_saw/queries.rb
|
210
231
|
- lib/table_saw/queries/foreign_key_relationships.rb
|
211
232
|
- lib/table_saw/queries/materialized_views.rb
|
212
233
|
- lib/table_saw/queries/no_id_tables.rb
|
@@ -1,97 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'table_saw/connection'
|
4
|
-
require 'table_saw/queries/foreign_key_relationships'
|
5
|
-
require 'table_saw/queries/no_id_tables'
|
6
|
-
|
7
|
-
module TableSaw
|
8
|
-
class BuildDependencyGraph
|
9
|
-
attr_reader :manifest, :records
|
10
|
-
|
11
|
-
def initialize(manifest)
|
12
|
-
@manifest = manifest
|
13
|
-
@records = Hash.new { |h, k| h[k] = [] }
|
14
|
-
end
|
15
|
-
|
16
|
-
def call
|
17
|
-
manifest.tables.each_value do |table|
|
18
|
-
add(table.name, perform_query(table.query).map { |row| row['id'] })
|
19
|
-
end
|
20
|
-
|
21
|
-
records
|
22
|
-
end
|
23
|
-
|
24
|
-
def add(table_name, ids)
|
25
|
-
return if ids.empty?
|
26
|
-
|
27
|
-
ids_to_add = ids - records[table_name]
|
28
|
-
return if ids_to_add.empty?
|
29
|
-
|
30
|
-
records[table_name].concat ids_to_add
|
31
|
-
fetch_belongs_to_associations(table_name, ids_to_add)
|
32
|
-
fetch_has_many_associations(table_name, ids_to_add)
|
33
|
-
end
|
34
|
-
|
35
|
-
# rubocop:disable Metrics/AbcSize
|
36
|
-
def fetch_belongs_to_associations(table_name, ids)
|
37
|
-
associations = belongs_to[table_name]
|
38
|
-
return if associations.empty?
|
39
|
-
|
40
|
-
rows = perform_query(
|
41
|
-
format('select %{columns} from %{table_name} where id in (%{ids})',
|
42
|
-
columns: associations.keys.join(','), table_name: table_name, ids: ids.join(','))
|
43
|
-
)
|
44
|
-
|
45
|
-
values = rows.each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |row, memo|
|
46
|
-
associations.each_key { |key| memo[key].add row[key] unless row[key].nil? }
|
47
|
-
end
|
48
|
-
|
49
|
-
associations.each { |from_column, to_table| add to_table, values[from_column].to_a }
|
50
|
-
end
|
51
|
-
# rubocop:enable Metrics/AbcSize
|
52
|
-
|
53
|
-
def fetch_has_many_associations(table_name, ids)
|
54
|
-
has_many.fetch(table_name, []).each do |table, column|
|
55
|
-
next if tables_with_no_ids.include?(table)
|
56
|
-
next unless has_many_mapping.fetch(table_name, []).include?(table)
|
57
|
-
|
58
|
-
rows = perform_query(
|
59
|
-
format('select id from %{table} where %{column} in (%{ids})',
|
60
|
-
table: table, column: column, ids: ids.join(','))
|
61
|
-
)
|
62
|
-
|
63
|
-
add(table, rows.map { |row| row['id'] })
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def perform_query(sql)
|
70
|
-
TableSaw::Connection.with do |conn|
|
71
|
-
conn.exec(sql)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def belongs_to
|
76
|
-
foreign_key_relationships.belongs_to
|
77
|
-
end
|
78
|
-
|
79
|
-
# rubocop:disable Naming/PredicateName
|
80
|
-
def has_many
|
81
|
-
foreign_key_relationships.has_many
|
82
|
-
end
|
83
|
-
|
84
|
-
def has_many_mapping
|
85
|
-
@has_many_mapping ||= manifest.tables.transform_values(&:has_many)
|
86
|
-
end
|
87
|
-
# rubocop:enable Naming/PredicateName
|
88
|
-
|
89
|
-
def foreign_key_relationships
|
90
|
-
@foreign_key_relationships ||= TableSaw::Queries::ForeignKeyRelationships.new
|
91
|
-
end
|
92
|
-
|
93
|
-
def tables_with_no_ids
|
94
|
-
@tables_with_no_ids ||= TableSaw::Queries::NoIdTables.new.call
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|