pgslice 0.4.2 → 0.4.3

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.
@@ -0,0 +1,89 @@
1
+ module PgSlice
2
+ class GenericTable
3
+ attr_reader :table
4
+
5
+ def initialize(table)
6
+ @table = table.to_s
7
+ end
8
+
9
+ def to_s
10
+ table
11
+ end
12
+
13
+ def exists?
14
+ existing_tables(like: table).any?
15
+ end
16
+
17
+ def columns
18
+ execute("SELECT column_name FROM information_schema.columns WHERE table_schema || '.' || table_name = $1", [table]).map{ |r| r["column_name"] }
19
+ end
20
+
21
+ # http://www.dbforums.com/showthread.php?1667561-How-to-list-sequences-and-the-columns-by-SQL
22
+ def sequences
23
+ query = <<-SQL
24
+ SELECT
25
+ a.attname as related_column,
26
+ s.relname as sequence_name
27
+ FROM pg_class s
28
+ JOIN pg_depend d ON d.objid = s.oid
29
+ JOIN pg_class t ON d.objid = s.oid AND d.refobjid = t.oid
30
+ JOIN pg_attribute a ON (d.refobjid, d.refobjsubid) = (a.attrelid, a.attnum)
31
+ JOIN pg_namespace n ON n.oid = s.relnamespace
32
+ WHERE s.relkind = 'S'
33
+ AND n.nspname = $1
34
+ AND t.relname = $2
35
+ SQL
36
+ execute(query, table.split(".", 2))
37
+ end
38
+
39
+ def foreign_keys
40
+ execute("SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conrelid = #{regclass(table)} AND contype ='f'").map { |r| r["pg_get_constraintdef"] }
41
+ end
42
+
43
+ # http://stackoverflow.com/a/20537829
44
+ def primary_key
45
+ query = <<-SQL
46
+ SELECT
47
+ pg_attribute.attname,
48
+ format_type(pg_attribute.atttypid, pg_attribute.atttypmod)
49
+ FROM
50
+ pg_index, pg_class, pg_attribute, pg_namespace
51
+ WHERE
52
+ nspname || '.' || relname = $1 AND
53
+ indrelid = pg_class.oid AND
54
+ pg_class.relnamespace = pg_namespace.oid AND
55
+ pg_attribute.attrelid = pg_class.oid AND
56
+ pg_attribute.attnum = any(pg_index.indkey) AND
57
+ indisprimary
58
+ SQL
59
+ execute(query, [table]).map { |r| r["attname"] }
60
+ end
61
+
62
+ def index_defs
63
+ execute("SELECT pg_get_indexdef(indexrelid) FROM pg_index WHERE indrelid = #{regclass(table)} AND indisprimary = 'f'").map { |r| r["pg_get_indexdef"] }
64
+ end
65
+
66
+ protected
67
+
68
+ def existing_tables(like:)
69
+ query = "SELECT schemaname, tablename FROM pg_catalog.pg_tables WHERE schemaname = $1 AND tablename LIKE $2"
70
+ execute(query, like.split(".", 2)).map { |r| "#{r["schemaname"]}.#{r["tablename"]}" }.sort
71
+ end
72
+
73
+ def execute(*args)
74
+ $client.send(:execute, *args)
75
+ end
76
+
77
+ def quote_ident(value)
78
+ PG::Connection.quote_ident(value)
79
+ end
80
+
81
+ def quote_table(table)
82
+ table.to_s.split(".", 2).map { |v| quote_ident(v) }.join(".")
83
+ end
84
+
85
+ def regclass(table)
86
+ "'#{quote_table(table)}'::regclass"
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,72 @@
1
+ module PgSlice
2
+ class Table < GenericTable
3
+ def intermediate_table
4
+ self.class.new("#{table}_intermediate")
5
+ end
6
+
7
+ def retired_table
8
+ self.class.new("#{table}_retired")
9
+ end
10
+
11
+ def trigger_name
12
+ "#{table.split(".")[-1]}_insert_trigger"
13
+ end
14
+
15
+ def column_cast(column)
16
+ data_type = execute("SELECT data_type FROM information_schema.columns WHERE table_schema || '.' || table_name = $1 AND column_name = $2", [table, column])[0]["data_type"]
17
+ data_type == "timestamp with time zone" ? "timestamptz" : "date"
18
+ end
19
+
20
+ def max_id(primary_key, below: nil, where: nil)
21
+ query = "SELECT MAX(#{quote_ident(primary_key)}) FROM #{quote_table(table)}"
22
+ conditions = []
23
+ conditions << "#{quote_ident(primary_key)} <= #{below}" if below
24
+ conditions << where if where
25
+ query << " WHERE #{conditions.join(" AND ")}" if conditions.any?
26
+ execute(query)[0]["max"].to_i
27
+ end
28
+
29
+ def min_id(primary_key, column, cast, starting_time, where)
30
+ query = "SELECT MIN(#{quote_ident(primary_key)}) FROM #{quote_table(table)}"
31
+ conditions = []
32
+ conditions << "#{quote_ident(column)} >= #{sql_date(starting_time, cast)}" if starting_time
33
+ conditions << where if where
34
+ query << " WHERE #{conditions.join(" AND ")}" if conditions.any?
35
+ (execute(query)[0]["min"] || 1).to_i
36
+ end
37
+
38
+ def existing_partitions(period = nil)
39
+ count =
40
+ case period
41
+ when "day"
42
+ 8
43
+ when "month"
44
+ 6
45
+ else
46
+ "6,8"
47
+ end
48
+
49
+ existing_tables(like: "#{table}_%").select { |t| /\A#{Regexp.escape("#{table}_")}\d{#{count}}\z/.match(t) }
50
+ end
51
+
52
+ def fetch_comment
53
+ execute("SELECT obj_description(#{regclass(table)}) AS comment")[0]
54
+ end
55
+
56
+ def fetch_trigger(trigger_name)
57
+ execute("SELECT obj_description(oid, 'pg_trigger') AS comment FROM pg_trigger WHERE tgname = $1 AND tgrelid = #{regclass(table)}", [trigger_name])[0]
58
+ end
59
+
60
+ protected
61
+
62
+ def sql_date(time, cast, add_cast = true)
63
+ if cast == "timestamptz"
64
+ fmt = "%Y-%m-%d %H:%M:%S UTC"
65
+ else
66
+ fmt = "%Y-%m-%d"
67
+ end
68
+ str = "'#{time.strftime(fmt)}'"
69
+ add_cast ? "#{str}::#{cast}" : str
70
+ end
71
+ end
72
+ end
@@ -1,3 +1,3 @@
1
1
  module PgSlice
2
- VERSION = "0.4.2"
2
+ VERSION = "0.4.3"
3
3
  end
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgslice
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-24 00:00:00.000000000 Z
11
+ date: 2018-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: slop
14
+ name: thor
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.0
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 0.18.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 0.18.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -92,6 +92,9 @@ files:
92
92
  - README.md
93
93
  - exe/pgslice
94
94
  - lib/pgslice.rb
95
+ - lib/pgslice/client.rb
96
+ - lib/pgslice/generic_table.rb
97
+ - lib/pgslice/table.rb
95
98
  - lib/pgslice/version.rb
96
99
  homepage: https://github.com/ankane/pgslice
97
100
  licenses: