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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68e7d2fca3250ae565d38d0709b1eb73d212b5e6af6c642702e6345123a55e3a
4
- data.tar.gz: 9d2340c8d9f285e97ffce51942c359843067c663f0383e0e4a9f752382b91eff
3
+ metadata.gz: 5c885ddde22232c3907a08da5411a55e09b1105a87afbac5aac0b2b443c63ee1
4
+ data.tar.gz: a8220ca48f1dea784d20e45ecc74dfd0f464c8524a55240715bb7154dc6f8879
5
5
  SHA512:
6
- metadata.gz: d124e944257073e9a37a1c39ef1a50ba64a86adc4f436312af1b69554a6b8ebdf36d0fedb375e89a9a521fc7e23f2c08f23bf80b15cdbe7c90c27e04542fc656
7
- data.tar.gz: 3cb9e58e2bd59553f94cee19af7f991f14174e8ee51fc8160eb923ebe467e54543a03b9d0895a6f09dd58489763af2b0299dbee3c6e04e8063af28502c17f2f1
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class PGSpecHelper
4
- VERSION = "1.4.0"
4
+ VERSION = "1.6.0"
5
5
  end
@@ -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.0
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-07-10 00:00:00.000000000 Z
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