table_saw 0.5.0 → 1.0.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 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