pg_spec_helper 1.6.0 → 1.7.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 +7 -0
- data/lib/pg_spec_helper/columns.rb +3 -3
- data/lib/pg_spec_helper/foreign_keys.rb +2 -2
- data/lib/pg_spec_helper/functions.rb +2 -2
- data/lib/pg_spec_helper/indexes.rb +2 -2
- data/lib/pg_spec_helper/primary_keys.rb +2 -2
- data/lib/pg_spec_helper/schemas.rb +3 -3
- data/lib/pg_spec_helper/tables.rb +3 -3
- data/lib/pg_spec_helper/triggers.rb +9 -12
- data/lib/pg_spec_helper/unique_constraints.rb +2 -2
- data/lib/pg_spec_helper/validations.rb +2 -2
- data/lib/pg_spec_helper/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2030740ae096125c106b944c0984652488f3b48f811aa5c4a4caa9f972099d6
|
4
|
+
data.tar.gz: b3e24f7888d0302b98b69aa7b6c2b52db6d4d3708c9cb060c30d5b41d0ab9bb8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d72899156ddd1196b5e1984c6ec3efb12eb1ea1372efe6975d44f9fb4181c948f65ab6b6b63e0b3cf2dc19743c4c7a14b1bb3057e94a2f424be13b2c3684472
|
7
|
+
data.tar.gz: c679e87bfd3fcdd08cec7516bf0388d02b159c4641ec023e08d1f1bd1e187726d74182d14f0a8ba15ca718e12ca7de967c0223a8c17fcc991413a9be6b9aa12f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [1.7.0](https://github.com/craigulliott/pg_spec_helper/compare/v1.6.0...v1.7.0) (2023-08-06)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* adding support for "instead of" in triggers ([488b4ab](https://github.com/craigulliott/pg_spec_helper/commit/488b4ab5fb458db2c7e2f60395b12dcfa9559459))
|
9
|
+
|
3
10
|
## [1.6.0](https://github.com/craigulliott/pg_spec_helper/compare/v1.5.0...v1.6.0) (2023-08-06)
|
4
11
|
|
5
12
|
|
@@ -8,7 +8,7 @@ class PGSpecHelper
|
|
8
8
|
# create a column for the provided table
|
9
9
|
def create_column schema_name, table_name, column_name, type, null = true
|
10
10
|
# note the `type` is safe from sql_injection due to the validation above
|
11
|
-
connection.exec(
|
11
|
+
connection.exec(<<~SQL)
|
12
12
|
ALTER TABLE #{connection.quote_ident schema_name.to_s}.#{connection.quote_ident table_name.to_s}
|
13
13
|
ADD COLUMN #{connection.quote_ident column_name.to_s} #{sanitize_name type} #{null ? "" : "NOT NULL"}
|
14
14
|
SQL
|
@@ -16,7 +16,7 @@ class PGSpecHelper
|
|
16
16
|
|
17
17
|
# return an array of column names for the provided table
|
18
18
|
def get_column_names schema_name, table_name
|
19
|
-
rows = connection.exec_params(
|
19
|
+
rows = connection.exec_params(<<~SQL, [schema_name.to_s, table_name.to_s])
|
20
20
|
SELECT column_name
|
21
21
|
FROM information_schema.columns
|
22
22
|
WHERE table_schema = $1
|
@@ -28,7 +28,7 @@ class PGSpecHelper
|
|
28
28
|
|
29
29
|
# return an array of column names for the provided table
|
30
30
|
def is_column_nullable schema_name, table_name, column_name
|
31
|
-
rows = connection.exec_params(
|
31
|
+
rows = connection.exec_params(<<~SQL, [schema_name.to_s, table_name.to_s, column_name.to_s])
|
32
32
|
SELECT is_nullable
|
33
33
|
FROM information_schema.columns
|
34
34
|
WHERE table_schema = $1
|
@@ -7,7 +7,7 @@ class PGSpecHelper
|
|
7
7
|
column_names_sql = column_names.map { |n| sanitize_name n }.join(", ")
|
8
8
|
foreign_column_names_sql = foreign_column_names.map { |n| sanitize_name n }.join(", ")
|
9
9
|
# add the foreign key
|
10
|
-
connection.exec(
|
10
|
+
connection.exec(<<~SQL)
|
11
11
|
ALTER TABLE #{sanitize_name schema_name}.#{sanitize_name table_name}
|
12
12
|
ADD CONSTRAINT #{sanitize_name foreign_key_name}
|
13
13
|
FOREIGN KEY (#{column_names_sql})
|
@@ -17,7 +17,7 @@ class PGSpecHelper
|
|
17
17
|
|
18
18
|
# returns a list of foreign keys for the provided table
|
19
19
|
def get_foreign_key_names schema_name, table_name
|
20
|
-
rows = connection.exec_params(
|
20
|
+
rows = connection.exec_params(<<~SQL, [schema_name.to_s, table_name.to_s])
|
21
21
|
SELECT constraint_name
|
22
22
|
FROM information_schema.table_constraints
|
23
23
|
WHERE table_schema = $1
|
@@ -4,7 +4,7 @@ class PGSpecHelper
|
|
4
4
|
module Functions
|
5
5
|
# create a function
|
6
6
|
def create_function schema_name, function_name, function_definition
|
7
|
-
connection.exec
|
7
|
+
connection.exec <<~SQL
|
8
8
|
CREATE FUNCTION #{schema_name}.#{function_name}() returns trigger language plpgsql AS $$
|
9
9
|
BEGIN
|
10
10
|
#{function_definition};
|
@@ -16,7 +16,7 @@ class PGSpecHelper
|
|
16
16
|
# return a list of function names for the provided schema
|
17
17
|
def get_function_names schema_name
|
18
18
|
# get the function names
|
19
|
-
rows = connection.exec(
|
19
|
+
rows = connection.exec(<<~SQL, [schema_name.to_s])
|
20
20
|
SELECT
|
21
21
|
routine_name
|
22
22
|
FROM
|
@@ -5,7 +5,7 @@ class PGSpecHelper
|
|
5
5
|
# Create an index
|
6
6
|
def create_index schema_name, table_name, column_names, index_name
|
7
7
|
column_names_sql = column_names.map { |n| sanitize_name n }.join(", ")
|
8
|
-
connection.exec(
|
8
|
+
connection.exec(<<~SQL)
|
9
9
|
CREATE INDEX #{connection.quote_ident index_name.to_s}
|
10
10
|
ON #{connection.quote_ident schema_name.to_s}.#{connection.quote_ident table_name.to_s} (#{column_names_sql})
|
11
11
|
SQL
|
@@ -13,7 +13,7 @@ class PGSpecHelper
|
|
13
13
|
|
14
14
|
# get a list of index names for the provided table
|
15
15
|
def get_index_names schema_name, table_name
|
16
|
-
rows = connection.exec_params(
|
16
|
+
rows = connection.exec_params(<<~SQL, [schema_name.to_s, table_name.to_s])
|
17
17
|
SELECT indexname
|
18
18
|
FROM pg_indexes
|
19
19
|
WHERE schemaname = $1
|
@@ -6,7 +6,7 @@ class PGSpecHelper
|
|
6
6
|
def create_primary_key schema_name, table_name, column_names, primary_key_name
|
7
7
|
column_names_sql = column_names.map { |n| connection.quote_ident n.to_s }.join(", ")
|
8
8
|
# add the primary_key
|
9
|
-
connection.exec(
|
9
|
+
connection.exec(<<~SQL)
|
10
10
|
ALTER TABLE #{sanitize_name schema_name.to_s}.#{sanitize_name table_name.to_s}
|
11
11
|
ADD CONSTRAINT #{sanitize_name primary_key_name}
|
12
12
|
PRIMARY KEY (#{column_names_sql})
|
@@ -16,7 +16,7 @@ class PGSpecHelper
|
|
16
16
|
# get the primary_key name for the provided table
|
17
17
|
def get_primary_key_name schema_name, table_name
|
18
18
|
# get the primary_key name
|
19
|
-
rows = connection.exec(
|
19
|
+
rows = connection.exec(<<~SQL, [schema_name.to_s, table_name.to_s])
|
20
20
|
SELECT
|
21
21
|
constraint_name
|
22
22
|
FROM
|
@@ -4,7 +4,7 @@ class PGSpecHelper
|
|
4
4
|
module Schemas
|
5
5
|
# create a new schema in the database
|
6
6
|
def create_schema schema_name
|
7
|
-
connection.exec(
|
7
|
+
connection.exec(<<~SQL)
|
8
8
|
CREATE SCHEMA #{connection.quote_ident schema_name.to_s};
|
9
9
|
SQL
|
10
10
|
end
|
@@ -13,7 +13,7 @@ class PGSpecHelper
|
|
13
13
|
def get_schema_names
|
14
14
|
ignored_schemas_sql = ignored_schemas.map { |n| sanitize_name n }.join("', '")
|
15
15
|
# return a list of the schema names from the database
|
16
|
-
results = connection.exec(
|
16
|
+
results = connection.exec(<<~SQL)
|
17
17
|
SELECT schema_name
|
18
18
|
FROM information_schema.schemata
|
19
19
|
WHERE
|
@@ -28,7 +28,7 @@ class PGSpecHelper
|
|
28
28
|
def delete_all_schemas
|
29
29
|
# delete all schemas except public
|
30
30
|
get_schema_names.reject { |schema_name| schema_name == :public }.each do |schema_name|
|
31
|
-
connection.exec(
|
31
|
+
connection.exec(<<~SQL)
|
32
32
|
-- temporarily set the client_min_messages to WARNING to
|
33
33
|
-- suppress the NOTICE messages about cascading deletes
|
34
34
|
SET client_min_messages TO WARNING;
|
@@ -4,7 +4,7 @@ class PGSpecHelper
|
|
4
4
|
module Tables
|
5
5
|
# create a new table in the provided schema
|
6
6
|
def create_table schema_name, table_name
|
7
|
-
connection.exec(
|
7
|
+
connection.exec(<<~SQL)
|
8
8
|
CREATE TABLE #{sanitize_name schema_name.to_s}.#{sanitize_name table_name.to_s}(
|
9
9
|
-- tables are created empty, and have columns added to them later
|
10
10
|
);
|
@@ -13,7 +13,7 @@ class PGSpecHelper
|
|
13
13
|
|
14
14
|
# return an array of table names for the provided schema
|
15
15
|
def get_table_names schema_name
|
16
|
-
rows = connection.exec_params(
|
16
|
+
rows = connection.exec_params(<<~SQL, [schema_name.to_s])
|
17
17
|
SELECT table_name FROM information_schema.tables
|
18
18
|
WHERE
|
19
19
|
table_schema = $1
|
@@ -26,7 +26,7 @@ class PGSpecHelper
|
|
26
26
|
# delete all tables in the provided schema
|
27
27
|
def delete_tables schema_name
|
28
28
|
get_table_names(schema_name).each do |table_name|
|
29
|
-
connection.exec(
|
29
|
+
connection.exec(<<~SQL)
|
30
30
|
-- temporarily set the client_min_messages to WARNING to
|
31
31
|
-- suppress the NOTICE messages about cascading deletes
|
32
32
|
SET client_min_messages TO WARNING;
|
@@ -6,18 +6,15 @@ class PGSpecHelper
|
|
6
6
|
class UnexpectedEventManipulationError < StandardError
|
7
7
|
end
|
8
8
|
|
9
|
-
class UnexpectedActionOrderError < StandardError
|
10
|
-
end
|
11
|
-
|
12
|
-
class UnexpectedActionStatementError < StandardError
|
13
|
-
end
|
14
|
-
|
15
9
|
class UnexpectedActionOrientationError < StandardError
|
16
10
|
end
|
17
11
|
|
18
12
|
class UnexpectedActionTimingError < StandardError
|
19
13
|
end
|
20
14
|
|
15
|
+
class UnexpectedConditionsError < StandardError
|
16
|
+
end
|
17
|
+
|
21
18
|
# create a postgres trigger
|
22
19
|
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
20
|
unless [:insert, :delete, :update].include? event_manipulation
|
@@ -25,19 +22,19 @@ class PGSpecHelper
|
|
25
22
|
end
|
26
23
|
|
27
24
|
unless action_condition.nil? || action_condition.is_a?(String)
|
28
|
-
raise
|
25
|
+
raise UnexpectedConditionsError, "expected String but got `#{action_condition}`"
|
29
26
|
end
|
30
27
|
|
31
28
|
unless [:row, :statement].include? action_orientation
|
32
29
|
raise UnexpectedActionOrientationError, action_orientation
|
33
30
|
end
|
34
31
|
|
35
|
-
unless [:before, :after].include? action_timing
|
32
|
+
unless [:before, :after, :instead_of].include? action_timing
|
36
33
|
raise UnexpectedActionTimingError, action_timing
|
37
34
|
end
|
38
35
|
|
39
|
-
#
|
40
|
-
timing_sql = "#{action_timing} #{event_manipulation}".upcase
|
36
|
+
# "INSTEAD OF/BEFORE/AFTER" "INSERT/UPDATE/DELETE"
|
37
|
+
timing_sql = "#{action_timing.to_s.sub("_", " ")} #{event_manipulation}".upcase
|
41
38
|
|
42
39
|
condition_sql = action_condition.nil? ? "" : "WHEN (#{action_condition})"
|
43
40
|
|
@@ -50,7 +47,7 @@ class PGSpecHelper
|
|
50
47
|
end
|
51
48
|
temp_tables_sql = temp_tables.any? ? "REFERENCING #{temp_tables.join(" ")}" : ""
|
52
49
|
|
53
|
-
connection.exec
|
50
|
+
connection.exec <<~SQL
|
54
51
|
-- trigger names only need to be unique for this table
|
55
52
|
CREATE TRIGGER #{name}
|
56
53
|
#{timing_sql} ON #{schema_name}.#{table_name} #{temp_tables_sql}
|
@@ -63,7 +60,7 @@ class PGSpecHelper
|
|
63
60
|
# return a list of trigger names for the provided table
|
64
61
|
def get_trigger_names schema_name, table_name
|
65
62
|
# get the trigger names
|
66
|
-
rows = connection.exec(
|
63
|
+
rows = connection.exec(<<~SQL, [schema_name.to_s, table_name.to_s])
|
67
64
|
SELECT
|
68
65
|
trigger_name
|
69
66
|
FROM
|
@@ -6,7 +6,7 @@ class PGSpecHelper
|
|
6
6
|
def create_unique_constraint schema_name, table_name, column_names, constraint_key_name
|
7
7
|
column_names_sql = column_names.map { |n| connection.quote_ident n.to_s }.join(", ")
|
8
8
|
# add the constraint key
|
9
|
-
connection.exec(
|
9
|
+
connection.exec(<<~SQL)
|
10
10
|
ALTER TABLE #{connection.quote_ident schema_name.to_s}.#{connection.quote_ident table_name.to_s}
|
11
11
|
ADD CONSTRAINT #{connection.quote_ident constraint_key_name.to_s}
|
12
12
|
UNIQUE (#{column_names_sql})
|
@@ -16,7 +16,7 @@ class PGSpecHelper
|
|
16
16
|
# get a list of unique constraints for the provided table
|
17
17
|
def get_unique_constraint_names schema_name, table_name
|
18
18
|
# get the unique constraint names
|
19
|
-
rows = connection.exec(
|
19
|
+
rows = connection.exec(<<~SQL, [schema_name.to_s, table_name.to_s])
|
20
20
|
SELECT
|
21
21
|
constraint_name
|
22
22
|
FROM
|
@@ -6,7 +6,7 @@ class PGSpecHelper
|
|
6
6
|
def create_validation schema_name, table_name, validation_name, check_clause
|
7
7
|
# todo the check_clause is vulnerable to sql injection (although this is very low risk because
|
8
8
|
# it is only ever provided by the test suite, and is never provided by the user)
|
9
|
-
connection.exec(
|
9
|
+
connection.exec(<<~SQL)
|
10
10
|
ALTER TABLE #{connection.quote_ident schema_name.to_s}.#{connection.quote_ident table_name.to_s}
|
11
11
|
ADD CONSTRAINT #{connection.quote_ident validation_name.to_s} CHECK (#{check_clause})
|
12
12
|
SQL
|
@@ -15,7 +15,7 @@ class PGSpecHelper
|
|
15
15
|
# return a list of validation names for the provided table
|
16
16
|
def get_validation_names schema_name, table_name
|
17
17
|
# get the validation names
|
18
|
-
rows = connection.exec(
|
18
|
+
rows = connection.exec(<<~SQL, [schema_name.to_s, table_name.to_s])
|
19
19
|
SELECT
|
20
20
|
constraint_name
|
21
21
|
FROM
|