table_saw 0.5.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb4c657ec087524b5db0ab9619be50b819d5b65ba1f410bfcc20b04cebc55123
4
- data.tar.gz: a82d41d12074742fa1a120322dca716d378d8ee1a5e78ca30820176f2e44b37a
3
+ metadata.gz: cf3632df0d6aab24f6fc503091fd5b571c4d755fd5bddbb31a31830eb5a8aba0
4
+ data.tar.gz: 3937c874285d79c122603e8f19d4ca0739a13b4713f251209c87e8fc6cf2ffab
5
5
  SHA512:
6
- metadata.gz: 1069f4020c08827258a12e14433e6782c2824c5e58917251433636f6e8b5ca5a951d0f67edc582cc893a36b6f3642dce484bd76649f01bdab2e4d750496c4607
7
- data.tar.gz: 4c7ff84820fdd86ebd72ceee70d22707bc39efe05264d7ee46888f2459b0433c769125e1d9142623265b02e300438d09d9ff53a92109b44e57e1ee55b7c0d81b
6
+ metadata.gz: 0c2f657b780d21fb9f53879f1bc99425517d19c56784dfbb980f3518ddf026d93bea02a11bd1ead2827666ed0b970916fc5c74f13fd9258a2b11bbb797b2e433
7
+ data.tar.gz: 77b8c86389378273c1b39a1a4fbbe7217c25dd9db576724f44621712e01d495038f7dd2f6a763ae46bcac0487f9cf1c240dcbc1a392f08017f5f4ba1771d7bae
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- table_saw (0.5.0)
4
+ table_saw (1.0.0)
5
5
  connection_pool
6
6
  pg
7
7
  thor
@@ -14,5 +14,11 @@ module TableSaw
14
14
  def self.pool
15
15
  @pool ||= ConnectionPool.new(size: 2) { PG::Connection.new(TableSaw.configuration.connection) }
16
16
  end
17
+
18
+ def self.exec(sql)
19
+ TableSaw::Connection.with do |conn|
20
+ conn.exec(sql)
21
+ end
22
+ end
17
23
  end
18
24
  end
@@ -21,6 +21,10 @@ module TableSaw
21
21
  def queryable?
22
22
  !partial || selectable?
23
23
  end
24
+
25
+ def primary_key
26
+ TableSaw.information_schema.primary_keys[table_name]
27
+ end
24
28
  end
25
29
  end
26
30
  end
@@ -3,10 +3,9 @@
3
3
  module TableSaw
4
4
  module DependencyGraph
5
5
  class BelongsToDirectives
6
- attr_reader :context, :directive
6
+ attr_reader :directive
7
7
 
8
- def initialize(context, directive)
9
- @context = context
8
+ def initialize(directive)
10
9
  @directive = directive
11
10
  end
12
11
 
@@ -19,7 +18,7 @@ module TableSaw
19
18
  private
20
19
 
21
20
  def associations
22
- context.belongs_to.fetch(directive.table_name, {})
21
+ TableSaw.information_schema.belongs_to.fetch(directive.table_name, {})
23
22
  end
24
23
 
25
24
  def ids
@@ -31,9 +30,10 @@ module TableSaw
31
30
  def query_result
32
31
  return [] unless directive.selectable?
33
32
 
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(','))
33
+ TableSaw::Connection.exec(
34
+ format('select %{columns} from %{table_name} where %{primary_key} in (%{ids})',
35
+ primary_key: directive.primary_key, columns: associations.keys.join(','),
36
+ table_name: directive.table_name, ids: directive.ids.join(','))
37
37
  )
38
38
  end
39
39
  end
@@ -32,19 +32,15 @@ module TableSaw
32
32
  if record
33
33
  dir.partial? ? record.fetch_associations(dir) : []
34
34
  else
35
- TableSaw::DependencyGraph::DumpTable.new(context: context, name: dir.table_name, partial: dir.partial?)
35
+ TableSaw::DependencyGraph::DumpTable.new(manifest: manifest, name: dir.table_name, partial: dir.partial?)
36
36
  .tap { |table| records[dir.table_name] = table }.fetch_associations(dir)
37
37
  end
38
38
  end
39
39
 
40
- def context
41
- @context ||= TableSaw::DependencyGraph::Context.new(manifest)
42
- end
43
-
44
40
  def select_ids(table)
45
41
  return [] unless table.partial?
46
42
 
47
- context.perform_query(table.query).map { |row| row['id'] }
43
+ TableSaw::Connection.exec(table.query).map { |row| row[TableSaw.information_schema.primary_keys[table.name]] }
48
44
  end
49
45
  end
50
46
  end
@@ -3,10 +3,10 @@
3
3
  module TableSaw
4
4
  module DependencyGraph
5
5
  class DumpTable
6
- attr_reader :context, :name, :partial, :ids
6
+ attr_reader :manifest, :name, :partial, :ids
7
7
 
8
- def initialize(context:, name:, partial: true)
9
- @context = context
8
+ def initialize(manifest:, name:, partial: true)
9
+ @manifest = manifest
10
10
  @name = name
11
11
  @partial = partial
12
12
  @ids = Set.new
@@ -14,7 +14,7 @@ module TableSaw
14
14
 
15
15
  def copy_statement
16
16
  if partial
17
- "select * from #{name} where id in (#{ids.to_a.join(',')})"
17
+ "select * from #{name} where #{primary_key} in (#{ids.to_a.join(',')})"
18
18
  else
19
19
  "select * from #{name}"
20
20
  end
@@ -29,11 +29,15 @@ module TableSaw
29
29
  private
30
30
 
31
31
  def fetch_belongs_to(directive)
32
- TableSaw::DependencyGraph::BelongsToDirectives.new(context, directive).call
32
+ TableSaw::DependencyGraph::BelongsToDirectives.new(directive).call
33
33
  end
34
34
 
35
35
  def fetch_has_many(directive)
36
- TableSaw::DependencyGraph::HasManyDirectives.new(context, directive).call
36
+ TableSaw::DependencyGraph::HasManyDirectives.new(manifest, directive).call
37
+ end
38
+
39
+ def primary_key
40
+ TableSaw.information_schema.primary_keys[name]
37
41
  end
38
42
  end
39
43
  end
@@ -3,17 +3,19 @@
3
3
  module TableSaw
4
4
  module DependencyGraph
5
5
  class HasManyDirectives
6
- attr_reader :context, :directive
6
+ attr_reader :manifest, :directive
7
7
 
8
- def initialize(context, directive)
9
- @context = context
8
+ def initialize(manifest, directive)
9
+ @manifest = manifest
10
10
  @directive = directive
11
11
  end
12
12
 
13
13
  def call
14
14
  valid_associations.map do |table, column|
15
15
  TableSaw::DependencyGraph::AddDirective.new(
16
- table, ids: query_result(table, column).map { |r| r['id'] }, partial: directive.partial?
16
+ table,
17
+ ids: query_result(table, column).map { |r| r[TableSaw.information_schema.primary_keys[table]] },
18
+ partial: directive.partial?
17
19
  )
18
20
  end
19
21
  end
@@ -21,23 +23,24 @@ module TableSaw
21
23
  private
22
24
 
23
25
  def associations
24
- context.has_many.fetch(directive.table_name, [])
26
+ TableSaw.information_schema.has_many.fetch(directive.table_name, [])
25
27
  end
26
28
 
27
29
  def valid_associations
28
30
  associations.select do |table, _column|
29
- next false if directive.partial? && context.tables_with_no_ids.include?(table)
31
+ next false if directive.partial? && !TableSaw.information_schema.primary_keys.key?(table)
30
32
 
31
- context.has_many_mapping.fetch(directive.table_name, []).include?(table)
33
+ manifest.has_many_mapping.fetch(directive.table_name, []).include?(table)
32
34
  end
33
35
  end
34
36
 
35
37
  def query_result(table, column)
36
38
  return [] unless directive.selectable?
37
39
 
38
- context.perform_query(
39
- format('select id from %{table} where %{column} in (%{ids})',
40
- table: table, column: column, ids: directive.ids.join(','))
40
+ TableSaw::Connection.exec(
41
+ format('select %{primary_key} from %{table} where %{column} in (%{ids})',
42
+ primary_key: TableSaw.information_schema.primary_keys[table], table: table, column: column,
43
+ ids: directive.ids.join(','))
41
44
  )
42
45
  end
43
46
  end
@@ -3,6 +3,5 @@
3
3
  require 'table_saw/dependency_graph/add_directive'
4
4
  require 'table_saw/dependency_graph/belongs_to_directives'
5
5
  require 'table_saw/dependency_graph/build'
6
- require 'table_saw/dependency_graph/context'
7
6
  require 'table_saw/dependency_graph/dump_table'
8
7
  require 'table_saw/dependency_graph/has_many_directives'
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableSaw
4
+ class InformationSchema
5
+ def belongs_to
6
+ foreign_key_relationships.belongs_to
7
+ end
8
+
9
+ # rubocop:disable Naming/PredicateName
10
+ def has_many
11
+ foreign_key_relationships.has_many
12
+ end
13
+ # rubocop:enable Naming/PredicateName
14
+
15
+ def primary_keys
16
+ @primary_keys ||= TableSaw::Queries::PrimaryKeys.new.call
17
+ end
18
+
19
+ private
20
+
21
+ def foreign_key_relationships
22
+ @foreign_key_relationships ||= TableSaw::Queries::ForeignKeyRelationships.new
23
+ end
24
+ end
25
+ end
@@ -19,18 +19,10 @@ module TableSaw
19
19
  alias name table
20
20
 
21
21
  def query
22
- if config['query']
23
- format(config['query'], variables.transform_keys(&:to_sym))
24
- else
25
- "select id from #{table}"
26
- end
27
- end
22
+ return unless partial?
28
23
 
29
- # rubocop:disable Naming/PredicateName
30
- def has_many
31
- config.fetch('has_many', [])
24
+ format(config['query'], variables.transform_keys(&:to_sym))
32
25
  end
33
- # rubocop:enable Naming/PredicateName
34
26
 
35
27
  def partial?
36
28
  config.key?('query')
@@ -58,5 +50,11 @@ module TableSaw
58
50
  memo[t.name] = t
59
51
  end
60
52
  end
53
+
54
+ # rubocop:disable Naming/PredicateName
55
+ def has_many_mapping
56
+ @has_many_mapping ||= config.fetch('has_many', {})
57
+ end
58
+ # rubocop:enable Naming/PredicateName
61
59
  end
62
60
  end
@@ -32,9 +32,7 @@ module TableSaw
32
32
  private
33
33
 
34
34
  def result
35
- @result ||= TableSaw::Connection.with do |conn|
36
- conn.exec(QUERY)
37
- end
35
+ @result ||= TableSaw::Connection.exec(QUERY)
38
36
  end
39
37
  end
40
38
  end
@@ -3,10 +3,10 @@
3
3
  module TableSaw
4
4
  module Queries
5
5
  class MaterializedViews
6
+ QUERY = 'select matviewname from pg_matviews order by matviewname'
7
+
6
8
  def call
7
- TableSaw::Connection.with do |conn|
8
- conn.exec('select matviewname from pg_matviews order by matviewname').map { |row| row['matviewname'] }
9
- end
9
+ TableSaw::Connection.exec(QUERY).map { |row| row['matviewname'] }
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TableSaw
4
+ module Queries
5
+ class PrimaryKeys
6
+ QUERY = <<~SQL
7
+ select tc.table_name, kcu.column_name
8
+ from information_schema.table_constraints tc
9
+ join information_schema.key_column_usage kcu using (constraint_schema, constraint_name)
10
+ where tc.constraint_type = 'PRIMARY KEY';
11
+ SQL
12
+
13
+ def call
14
+ TableSaw::Connection.exec(QUERY).each_with_object({}) do |row, memo|
15
+ memo[row['table_name']] = row['column_name']
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -18,10 +18,8 @@ module TableSaw
18
18
  SerialSequence = Struct.new(:name, :table, :column)
19
19
 
20
20
  def call
21
- TableSaw::Connection.with do |conn|
22
- conn.exec(QUERY).each_with_object({}) do |row, memo|
23
- memo[row['table']] = SerialSequence.new(row['sequence'], row['table'], row['column'])
24
- end
21
+ TableSaw::Connection.exec(QUERY).each_with_object({}) do |row, memo|
22
+ memo[row['table']] = SerialSequence.new(row['sequence'], row['table'], row['column'])
25
23
  end
26
24
  end
27
25
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  require 'table_saw/queries/foreign_key_relationships'
4
4
  require 'table_saw/queries/materialized_views'
5
- require 'table_saw/queries/no_id_tables'
5
+ require 'table_saw/queries/primary_keys'
6
6
  require 'table_saw/queries/serial_sequences'
7
7
  require 'table_saw/queries/table_columns'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TableSaw
4
- VERSION = '0.5.0'
4
+ VERSION = '1.0.0'
5
5
  end
data/lib/table_saw.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'table_saw/configuration'
4
4
  require 'table_saw/connection'
5
5
  require 'table_saw/dependency_graph'
6
+ require 'table_saw/information_schema'
6
7
  require 'table_saw/manifest'
7
8
  require 'table_saw/queries'
8
9
 
@@ -20,4 +21,8 @@ module TableSaw
20
21
  end
21
22
  end
22
23
  end
24
+
25
+ def self.information_schema
26
+ @information_schema ||= TableSaw::InformationSchema.new
27
+ end
23
28
  end
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.5.0
4
+ version: 1.0.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-18 00:00:00.000000000 Z
11
+ date: 2019-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: connection_pool
@@ -223,14 +223,14 @@ files:
223
223
  - lib/table_saw/dependency_graph/add_directive.rb
224
224
  - lib/table_saw/dependency_graph/belongs_to_directives.rb
225
225
  - lib/table_saw/dependency_graph/build.rb
226
- - lib/table_saw/dependency_graph/context.rb
227
226
  - lib/table_saw/dependency_graph/dump_table.rb
228
227
  - lib/table_saw/dependency_graph/has_many_directives.rb
228
+ - lib/table_saw/information_schema.rb
229
229
  - lib/table_saw/manifest.rb
230
230
  - lib/table_saw/queries.rb
231
231
  - lib/table_saw/queries/foreign_key_relationships.rb
232
232
  - lib/table_saw/queries/materialized_views.rb
233
- - lib/table_saw/queries/no_id_tables.rb
233
+ - lib/table_saw/queries/primary_keys.rb
234
234
  - lib/table_saw/queries/serial_sequences.rb
235
235
  - lib/table_saw/queries/table_columns.rb
236
236
  - lib/table_saw/version.rb
@@ -1,42 +0,0 @@
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
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TableSaw
4
- module Queries
5
- class NoIdTables
6
- QUERY = <<~SQL
7
- select t.table_name
8
- from information_schema.tables t left outer join information_schema.table_constraints tc
9
- on t.table_name = tc.table_name and tc.constraint_type = 'PRIMARY KEY'
10
- where t.table_schema = 'public' and table_type = 'BASE TABLE' and tc.table_name IS NULL
11
- SQL
12
-
13
- def call
14
- TableSaw::Connection.with do |conn|
15
- conn.exec(QUERY)
16
- end
17
- end
18
- end
19
- end
20
- end