pg_spec_helper 1.4.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/pg_spec_helper/columns.rb +18 -2
- data/lib/pg_spec_helper/functions.rb +30 -0
- data/lib/pg_spec_helper/models.rb +35 -0
- data/lib/pg_spec_helper/table_executer.rb +36 -0
- data/lib/pg_spec_helper/triggers.rb +78 -0
- data/lib/pg_spec_helper/version.rb +1 -1
- data/lib/pg_spec_helper.rb +8 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c885ddde22232c3907a08da5411a55e09b1105a87afbac5aac0b2b443c63ee1
|
4
|
+
data.tar.gz: a8220ca48f1dea784d20e45ecc74dfd0f464c8524a55240715bb7154dc6f8879
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08770ab6431e7b5d2f21b0443d88282400ea597d78b946fe5c68b4c4ff562ae7bd14e0ddb5db4c5353ec8954ee0472ce5e5a2858259186504469f0a6783d66df'
|
7
|
+
data.tar.gz: f811831ee0dc0381a3252556d28c1ac85f476707ab3ac6fd3c951c0c2ecb985ea7d18a1daf663d27ce533c06cab94e91d0963a200a88590bae5004a14d64b0d7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [1.6.0](https://github.com/craigulliott/pg_spec_helper/compare/v1.5.0...v1.6.0) (2023-08-06)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* added support for triggers and functions ([f89bf5e](https://github.com/craigulliott/pg_spec_helper/commit/f89bf5e3afa6fc411e9d1f16cb62db74fc8dc987))
|
9
|
+
|
10
|
+
## [1.5.0](https://github.com/craigulliott/pg_spec_helper/compare/v1.4.0...v1.5.0) (2023-08-01)
|
11
|
+
|
12
|
+
|
13
|
+
### Features
|
14
|
+
|
15
|
+
* adding a new create_model method which yields a block to expose a DSL for easily working with the table structure ([dc28d5e](https://github.com/craigulliott/pg_spec_helper/commit/dc28d5ef599d8306564aa7c29d2220fb22ee6dd6))
|
16
|
+
|
3
17
|
## [1.4.0](https://github.com/craigulliott/pg_spec_helper/compare/v1.3.0...v1.4.0) (2023-07-10)
|
4
18
|
|
5
19
|
|
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
class PGSpecHelper
|
4
4
|
module Columns
|
5
|
+
class ColumnDoesNotExistError < StandardError
|
6
|
+
end
|
7
|
+
|
5
8
|
# create a column for the provided table
|
6
|
-
def create_column schema_name, table_name, column_name, type
|
9
|
+
def create_column schema_name, table_name, column_name, type, null = true
|
7
10
|
# note the `type` is safe from sql_injection due to the validation above
|
8
11
|
connection.exec(<<-SQL)
|
9
12
|
ALTER TABLE #{connection.quote_ident schema_name.to_s}.#{connection.quote_ident table_name.to_s}
|
10
|
-
ADD COLUMN #{connection.quote_ident column_name.to_s} #{sanitize_name type}
|
13
|
+
ADD COLUMN #{connection.quote_ident column_name.to_s} #{sanitize_name type} #{null ? "" : "NOT NULL"}
|
11
14
|
SQL
|
12
15
|
end
|
13
16
|
|
@@ -22,5 +25,18 @@ class PGSpecHelper
|
|
22
25
|
SQL
|
23
26
|
rows.map { |row| row["column_name"].to_sym }
|
24
27
|
end
|
28
|
+
|
29
|
+
# return an array of column names for the provided table
|
30
|
+
def is_column_nullable schema_name, table_name, column_name
|
31
|
+
rows = connection.exec_params(<<-SQL, [schema_name.to_s, table_name.to_s, column_name.to_s])
|
32
|
+
SELECT is_nullable
|
33
|
+
FROM information_schema.columns
|
34
|
+
WHERE table_schema = $1
|
35
|
+
AND table_name = $2
|
36
|
+
AND column_name = $3;
|
37
|
+
SQL
|
38
|
+
raise ColumnDoesNotExistError if rows.first.nil?
|
39
|
+
rows.first["is_nullable"] == "YES"
|
40
|
+
end
|
25
41
|
end
|
26
42
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PGSpecHelper
|
4
|
+
module Functions
|
5
|
+
# create a function
|
6
|
+
def create_function schema_name, function_name, function_definition
|
7
|
+
connection.exec <<-SQL
|
8
|
+
CREATE FUNCTION #{schema_name}.#{function_name}() returns trigger language plpgsql AS $$
|
9
|
+
BEGIN
|
10
|
+
#{function_definition};
|
11
|
+
RETURN NEW;
|
12
|
+
END $$;
|
13
|
+
SQL
|
14
|
+
end
|
15
|
+
|
16
|
+
# return a list of function names for the provided schema
|
17
|
+
def get_function_names schema_name
|
18
|
+
# get the function names
|
19
|
+
rows = connection.exec(<<-SQL, [schema_name.to_s])
|
20
|
+
SELECT
|
21
|
+
routine_name
|
22
|
+
FROM
|
23
|
+
information_schema.routines
|
24
|
+
WHERE
|
25
|
+
routine_schema = $1
|
26
|
+
SQL
|
27
|
+
rows.map { |r| r["routine_name"].to_sym }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PGSpecHelper
|
4
|
+
module Models
|
5
|
+
# create a new table in the provided schema with an auto incrementing id
|
6
|
+
# created_at and updated_at, optionally provide a block which will be
|
7
|
+
# yeilded This allows for syntax such as:
|
8
|
+
#
|
9
|
+
# create_model :users, :optional_schema_name do |t|
|
10
|
+
# t.add_colmn string :name
|
11
|
+
# end
|
12
|
+
def create_model schema_name, table_name, &block
|
13
|
+
unless schema_exists? schema_name
|
14
|
+
create_schema schema_name
|
15
|
+
end
|
16
|
+
# create the table
|
17
|
+
create_table schema_name, table_name
|
18
|
+
# create the standard columns
|
19
|
+
create_column schema_name, table_name, :id, :serial
|
20
|
+
create_column schema_name, table_name, :created_at, :timestamp
|
21
|
+
create_column schema_name, table_name, :updated_at, :timestamp
|
22
|
+
# add the primary key
|
23
|
+
create_primary_key schema_name, table_name, [:id], :pk
|
24
|
+
# execute the optional block
|
25
|
+
if block
|
26
|
+
this = self
|
27
|
+
if this.is_a? PGSpecHelper
|
28
|
+
TableExecuter.new(this, schema_name, table_name, &block)
|
29
|
+
else
|
30
|
+
raise "Module should be added to PGSpecHelper"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PGSpecHelper
|
4
|
+
class TableExecuter
|
5
|
+
def initialize pg_spec_helper, schema_name, table_name, &block
|
6
|
+
@pg_spec_helper = pg_spec_helper
|
7
|
+
@schema_name = schema_name
|
8
|
+
@table_name = table_name
|
9
|
+
instance_exec(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_column column_name, type, null = true
|
13
|
+
@pg_spec_helper.create_column @schema_name, @table_name, column_name, type, null
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_foreign_key column_names, foreign_schema_name, foreign_table_name, foreign_column_names, foreign_key_name
|
17
|
+
@pg_spec_helper.create_foreign_key @schema_name, @table_name, column_names, foreign_schema_name, foreign_table_name, foreign_column_names, foreign_key_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_index column_names, index_name, unique = false
|
21
|
+
@pg_spec_helper.create_index @schema_name, @table_name, column_names, index_name
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_primary_key column_names, primary_key_name
|
25
|
+
@pg_spec_helper.create_primary_key @schema_name, @table_name, column_names, primary_key_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_unique_constraint column_names, constraint_key_name
|
29
|
+
@pg_spec_helper.create_unique_constraint @schema_name, @table_name, column_names, constraint_key_name
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_validation validation_name, check_clause
|
33
|
+
@pg_spec_helper.create_validation @schema_name, @table_name, validation_name, check_clause
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class PGSpecHelper
|
4
|
+
module Triggers
|
5
|
+
# create a trigger
|
6
|
+
class UnexpectedEventManipulationError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
class UnexpectedActionOrderError < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
class UnexpectedActionStatementError < StandardError
|
13
|
+
end
|
14
|
+
|
15
|
+
class UnexpectedActionOrientationError < StandardError
|
16
|
+
end
|
17
|
+
|
18
|
+
class UnexpectedActionTimingError < StandardError
|
19
|
+
end
|
20
|
+
|
21
|
+
# create a postgres trigger
|
22
|
+
def create_trigger schema_name, table_name, name, action_timing:, event_manipulation:, action_orientation:, routine_schema:, routine_name:, action_condition: nil, action_reference_old_table: nil, action_reference_new_table: nil
|
23
|
+
unless [:insert, :delete, :update].include? event_manipulation
|
24
|
+
raise UnexpectedEventManipulationError, event_manipulation
|
25
|
+
end
|
26
|
+
|
27
|
+
unless action_condition.nil? || action_condition.is_a?(String)
|
28
|
+
raise ExpectedStringError, action_condition
|
29
|
+
end
|
30
|
+
|
31
|
+
unless [:row, :statement].include? action_orientation
|
32
|
+
raise UnexpectedActionOrientationError, action_orientation
|
33
|
+
end
|
34
|
+
|
35
|
+
unless [:before, :after].include? action_timing
|
36
|
+
raise UnexpectedActionTimingError, action_timing
|
37
|
+
end
|
38
|
+
|
39
|
+
# BEFORE INSERT / AFTER INSERT / BEFORE UPDATE / AFTER UPDATE / BEFORE DELETE / AFTER DELETE
|
40
|
+
timing_sql = "#{action_timing} #{event_manipulation}".upcase
|
41
|
+
|
42
|
+
condition_sql = action_condition.nil? ? "" : "WHEN (#{action_condition})"
|
43
|
+
|
44
|
+
temp_tables = []
|
45
|
+
unless action_reference_old_table.nil?
|
46
|
+
temp_tables << "OLD TABLE AS #{action_reference_old_table}"
|
47
|
+
end
|
48
|
+
unless action_reference_new_table.nil?
|
49
|
+
temp_tables << "NEW TABLE AS #{action_reference_new_table}"
|
50
|
+
end
|
51
|
+
temp_tables_sql = temp_tables.any? ? "REFERENCING #{temp_tables.join(" ")}" : ""
|
52
|
+
|
53
|
+
connection.exec <<-SQL
|
54
|
+
-- trigger names only need to be unique for this table
|
55
|
+
CREATE TRIGGER #{name}
|
56
|
+
#{timing_sql} ON #{schema_name}.#{table_name} #{temp_tables_sql}
|
57
|
+
FOR EACH #{action_orientation}
|
58
|
+
#{condition_sql}
|
59
|
+
EXECUTE PROCEDURE #{routine_schema}.#{routine_name}();
|
60
|
+
SQL
|
61
|
+
end
|
62
|
+
|
63
|
+
# return a list of trigger names for the provided table
|
64
|
+
def get_trigger_names schema_name, table_name
|
65
|
+
# get the trigger names
|
66
|
+
rows = connection.exec(<<-SQL, [schema_name.to_s, table_name.to_s])
|
67
|
+
SELECT
|
68
|
+
trigger_name
|
69
|
+
FROM
|
70
|
+
information_schema.triggers
|
71
|
+
WHERE
|
72
|
+
event_object_schema = $1
|
73
|
+
AND event_object_table = $2
|
74
|
+
SQL
|
75
|
+
rows.map { |r| r["trigger_name"].to_sym }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/pg_spec_helper.rb
CHANGED
@@ -16,11 +16,16 @@ require "pg_spec_helper/foreign_keys"
|
|
16
16
|
require "pg_spec_helper/unique_constraints"
|
17
17
|
require "pg_spec_helper/primary_keys"
|
18
18
|
require "pg_spec_helper/indexes"
|
19
|
+
require "pg_spec_helper/triggers"
|
20
|
+
require "pg_spec_helper/functions"
|
21
|
+
require "pg_spec_helper/models"
|
19
22
|
require "pg_spec_helper/materialized_views"
|
20
23
|
require "pg_spec_helper/reset"
|
21
24
|
require "pg_spec_helper/empty_database"
|
22
25
|
require "pg_spec_helper/track_changes"
|
23
26
|
|
27
|
+
require "pg_spec_helper/table_executer"
|
28
|
+
|
24
29
|
class PGSpecHelper
|
25
30
|
class MissingRequiredOptionError < StandardError
|
26
31
|
end
|
@@ -36,6 +41,9 @@ class PGSpecHelper
|
|
36
41
|
include UniqueConstraints
|
37
42
|
include PrimaryKeys
|
38
43
|
include Indexes
|
44
|
+
include Triggers
|
45
|
+
include Functions
|
46
|
+
include Models
|
39
47
|
include MaterializedViews
|
40
48
|
include Reset
|
41
49
|
include EmptyDatabase
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_spec_helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Craig Ulliott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -55,15 +55,19 @@ files:
|
|
55
55
|
- lib/pg_spec_helper/connection.rb
|
56
56
|
- lib/pg_spec_helper/empty_database.rb
|
57
57
|
- lib/pg_spec_helper/foreign_keys.rb
|
58
|
+
- lib/pg_spec_helper/functions.rb
|
58
59
|
- lib/pg_spec_helper/ignored_schemas.rb
|
59
60
|
- lib/pg_spec_helper/indexes.rb
|
60
61
|
- lib/pg_spec_helper/materialized_views.rb
|
62
|
+
- lib/pg_spec_helper/models.rb
|
61
63
|
- lib/pg_spec_helper/primary_keys.rb
|
62
64
|
- lib/pg_spec_helper/reset.rb
|
63
65
|
- lib/pg_spec_helper/sanitize.rb
|
64
66
|
- lib/pg_spec_helper/schemas.rb
|
67
|
+
- lib/pg_spec_helper/table_executer.rb
|
65
68
|
- lib/pg_spec_helper/tables.rb
|
66
69
|
- lib/pg_spec_helper/track_changes.rb
|
70
|
+
- lib/pg_spec_helper/triggers.rb
|
67
71
|
- lib/pg_spec_helper/unique_constraints.rb
|
68
72
|
- lib/pg_spec_helper/validations.rb
|
69
73
|
- lib/pg_spec_helper/version.rb
|