pgslice 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: