pg_spec_helper 1.4.0 → 1.6.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 +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
|