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