hoardable 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.tool-versions +1 -1
- data/CHANGELOG.md +4 -2
- data/README.md +3 -3
- data/lib/generators/hoardable/functions/hoardable_prevent_update_id.sql +8 -0
- data/lib/generators/hoardable/functions/hoardable_source_set_id.sql +18 -0
- data/lib/generators/hoardable/functions/hoardable_version_prevent_update.sql +6 -0
- data/lib/generators/hoardable/install_generator.rb +16 -2
- data/lib/generators/hoardable/migration_generator.rb +19 -1
- data/lib/generators/hoardable/templates/install.rb.erb +28 -59
- data/lib/generators/hoardable/templates/migration.rb.erb +7 -26
- data/lib/generators/hoardable/triggers/prevent_update_hoardable_id.sql +3 -0
- data/lib/generators/hoardable/triggers/set_hoardable_id.sql +3 -0
- data/lib/generators/hoardable/triggers/versions_prevent_update.sql +3 -0
- data/lib/hoardable/version.rb +1 -1
- metadata +30 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83017b15a9b37931d02d7f5d8b7b8d3e81cab4b4cc4691f522430ae2c9be77f8
|
4
|
+
data.tar.gz: 1774bb8cfe7628bbc2bdd8293928dac45dce20c4724aa5c4bc435a4c59a40f0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0b7d0024a9b8eee5982ab92af174a9a7a134445108c1c3d97945c5ad967f234743fe047f0c42726366d38b7facacc44bac530a5de9a5369de0a9e7bc27342f9
|
7
|
+
data.tar.gz: fb4d0de48b7d798e70c948aea4ae8adb90eaa2836c4ca2d76e952e5c02d53951205f2628bc3e620cb1824f6ac49fcc692dc19130f907c932e0ed3b78fee217e8
|
data/.rubocop.yml
CHANGED
data/.tool-versions
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
ruby 3.1
|
1
|
+
ruby 3.2.1
|
2
2
|
postgres 14.4
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Hoardable ![gem version](https://img.shields.io/gem/v/hoardable?style=flat-square)
|
2
2
|
|
3
|
-
Hoardable is an ActiveRecord extension for Ruby 2.
|
3
|
+
Hoardable is an ActiveRecord extension for Ruby 2.7+, Rails 6.1+, and PostgreSQL that allows for versioning
|
4
4
|
and soft-deletion of records through the use of _uni-temporal inherited tables_.
|
5
5
|
|
6
6
|
[Temporal tables](https://en.wikipedia.org/wiki/Temporal_database) are a database design pattern where each
|
@@ -34,8 +34,8 @@ bin/rails g hoardable:install
|
|
34
34
|
bin/rails db:migrate
|
35
35
|
```
|
36
36
|
|
37
|
-
This will generate PostgreSQL functions, an
|
38
|
-
in `application.rb
|
37
|
+
This will generate PostgreSQL functions, an enum and an initiailzer. It will also set
|
38
|
+
`config.active_record.schema_format = :sql` in `application.rb` if you are using Rails < 7.
|
39
39
|
|
40
40
|
### Model Installation
|
41
41
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
CREATE OR REPLACE FUNCTION hoardable_source_set_id() RETURNS trigger
|
2
|
+
LANGUAGE plpgsql AS
|
3
|
+
$$
|
4
|
+
DECLARE
|
5
|
+
_pk information_schema.constraint_column_usage.column_name%TYPE;
|
6
|
+
_id _pk%TYPE;
|
7
|
+
BEGIN
|
8
|
+
SELECT c.column_name
|
9
|
+
FROM information_schema.table_constraints t
|
10
|
+
JOIN information_schema.constraint_column_usage c
|
11
|
+
ON c.constraint_name = t.constraint_name
|
12
|
+
WHERE c.table_name = TG_TABLE_NAME AND t.constraint_type = 'PRIMARY KEY'
|
13
|
+
LIMIT 1
|
14
|
+
INTO _pk;
|
15
|
+
EXECUTE format('SELECT $1.%I', _pk) INTO _id USING NEW;
|
16
|
+
NEW.hoardable_id = _id;
|
17
|
+
RETURN NEW;
|
18
|
+
END;$$;
|
@@ -8,6 +8,7 @@ module Hoardable
|
|
8
8
|
class InstallGenerator < Rails::Generators::Base
|
9
9
|
source_root File.expand_path('templates', __dir__)
|
10
10
|
include Rails::Generators::Migration
|
11
|
+
delegate :supports_schema_enums?, to: :class
|
11
12
|
|
12
13
|
def create_initializer_file
|
13
14
|
create_file(
|
@@ -22,12 +23,25 @@ module Hoardable
|
|
22
23
|
)
|
23
24
|
end
|
24
25
|
|
26
|
+
def change_schema_format_to_sql
|
27
|
+
return if supports_schema_enums?
|
28
|
+
|
29
|
+
application 'config.active_record.schema_format = :sql'
|
30
|
+
end
|
31
|
+
|
25
32
|
def create_migration_file
|
26
33
|
migration_template 'install.rb.erb', 'db/migrate/install_hoardable.rb'
|
27
34
|
end
|
28
35
|
|
29
|
-
def
|
30
|
-
|
36
|
+
def create_functions
|
37
|
+
Dir.glob(File.join(__dir__, 'functions', '*.sql')).each do |file_path|
|
38
|
+
file_name = file_path.match(%r{([^/]+)\.sql})[1]
|
39
|
+
template file_path, "db/functions/#{file_name}_v01.sql"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.supports_schema_enums?
|
44
|
+
ActiveRecord.version >= ::Gem::Version.new('7.0.0')
|
31
45
|
end
|
32
46
|
|
33
47
|
def self.next_migration_number(dir)
|
@@ -9,12 +9,30 @@ module Hoardable
|
|
9
9
|
class MigrationGenerator < ActiveRecord::Generators::Base
|
10
10
|
source_root File.expand_path('templates', __dir__)
|
11
11
|
include Rails::Generators::Migration
|
12
|
-
class_option
|
12
|
+
class_option(
|
13
|
+
:foreign_key_type,
|
14
|
+
type: :string,
|
15
|
+
optional: true,
|
16
|
+
desc: 'explictly set / override the foreign key type of the versions table'
|
17
|
+
)
|
13
18
|
|
14
19
|
def create_versions_table
|
15
20
|
migration_template 'migration.rb.erb', "db/migrate/create_#{singularized_table_name}_versions.rb"
|
16
21
|
end
|
17
22
|
|
23
|
+
def create_triggers
|
24
|
+
{
|
25
|
+
versions_prevent_update: singularized_table_name,
|
26
|
+
set_hoardable_id: table_name,
|
27
|
+
prevent_update_hoardable_id: table_name
|
28
|
+
}.each do |(trigger_name, trigger_table_name)|
|
29
|
+
template(
|
30
|
+
"../triggers/#{trigger_name}.sql",
|
31
|
+
"db/triggers/#{trigger_table_name}_#{trigger_name}_v01.sql"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
18
36
|
no_tasks do
|
19
37
|
def foreign_key_type
|
20
38
|
options[:foreign_key_type] ||
|
@@ -1,65 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class InstallHoardable < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
4
|
+
def change
|
5
|
+
create_function :hoardable_prevent_update_id
|
6
|
+
create_function :hoardable_source_set_id
|
7
|
+
create_function :hoardable_version_prevent_update
|
8
|
+
<% if supports_schema_enums? %>
|
9
|
+
create_enum :hoardable_operation, %w[update delete insert]
|
10
|
+
<% else %>
|
11
|
+
reversible do |dir|
|
12
|
+
dir.up do
|
13
|
+
execute(
|
14
|
+
<<~SQL.squish
|
15
|
+
DO $$
|
16
|
+
BEGIN
|
17
|
+
IF NOT EXISTS (
|
18
|
+
SELECT 1 FROM pg_type t WHERE t.typname = 'hoardable_operation'
|
19
|
+
) THEN
|
20
|
+
CREATE TYPE hoardable_operation AS ENUM ('update', 'delete', 'insert');
|
21
|
+
END IF;
|
22
|
+
END
|
23
|
+
$$;
|
24
|
+
SQL
|
25
|
+
)
|
26
|
+
end
|
16
27
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
_id _pk%TYPE;
|
23
|
-
BEGIN
|
24
|
-
SELECT c.column_name
|
25
|
-
FROM information_schema.table_constraints t
|
26
|
-
JOIN information_schema.constraint_column_usage c
|
27
|
-
ON c.constraint_name = t.constraint_name
|
28
|
-
WHERE c.table_name = TG_TABLE_NAME AND t.constraint_type = 'PRIMARY KEY'
|
29
|
-
LIMIT 1
|
30
|
-
INTO _pk;
|
31
|
-
EXECUTE format('SELECT $1.%I', _pk) INTO _id USING NEW;
|
32
|
-
NEW.hoardable_id = _id;
|
33
|
-
RETURN NEW;
|
34
|
-
END;$$;
|
35
|
-
|
36
|
-
CREATE OR REPLACE FUNCTION hoardable_prevent_update_id() RETURNS trigger
|
37
|
-
LANGUAGE plpgsql AS
|
38
|
-
$$BEGIN
|
39
|
-
IF NEW.hoardable_id <> OLD.hoardable_id THEN
|
40
|
-
RAISE EXCEPTION 'hoardable id cannot be updated';
|
41
|
-
END IF;
|
42
|
-
RETURN NEW;
|
43
|
-
END;$$;
|
44
|
-
|
45
|
-
CREATE OR REPLACE FUNCTION hoardable_version_prevent_update() RETURNS trigger
|
46
|
-
LANGUAGE plpgsql AS
|
47
|
-
$$BEGIN
|
48
|
-
RAISE EXCEPTION 'updating a version is not allowed';
|
49
|
-
RETURN NEW;
|
50
|
-
END;$$;
|
51
|
-
SQL
|
52
|
-
)
|
53
|
-
end
|
54
|
-
|
55
|
-
def down
|
56
|
-
execute(
|
57
|
-
<<~SQL.squish
|
58
|
-
DROP TYPE IF EXISTS hoardable_operation;
|
59
|
-
DROP FUNCTION IF EXISTS hoardable_version_prevent_update();
|
60
|
-
DROP FUNCTION IF EXISTS hoardable_source_set_id();
|
61
|
-
DROP FUNCTION IF EXISTS hoardable_prevent_update_id();
|
62
|
-
SQL
|
63
|
-
)
|
28
|
+
dir.down do
|
29
|
+
execute('DROP TYPE IF EXISTS hoardable_operation;')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
<% end %>
|
64
33
|
end
|
65
34
|
end
|
@@ -12,34 +12,15 @@ class Create<%= class_name.singularize.delete(':') %>Versions < ActiveRecord::Mi
|
|
12
12
|
end
|
13
13
|
reversible do |dir|
|
14
14
|
dir.up do
|
15
|
-
execute(
|
16
|
-
<<~SQL
|
17
|
-
UPDATE <%= table_name %> SET hoardable_id = <%= primary_key %>;
|
18
|
-
CREATE TRIGGER <%= singularized_table_name %>_versions_prevent_update
|
19
|
-
BEFORE UPDATE ON <%= singularized_table_name %>_versions FOR EACH ROW
|
20
|
-
EXECUTE PROCEDURE hoardable_version_prevent_update();
|
21
|
-
CREATE TRIGGER <%= table_name %>_set_hoardable_id
|
22
|
-
BEFORE INSERT ON <%= table_name %> FOR EACH ROW
|
23
|
-
EXECUTE PROCEDURE hoardable_source_set_id();
|
24
|
-
CREATE TRIGGER <%= table_name %>_prevent_update_hoardable_id
|
25
|
-
BEFORE UPDATE ON <%= table_name %> FOR EACH ROW
|
26
|
-
EXECUTE PROCEDURE hoardable_prevent_update_id();
|
27
|
-
SQL
|
28
|
-
)
|
29
|
-
end
|
30
|
-
dir.down do
|
31
|
-
execute(
|
32
|
-
<<~SQL
|
33
|
-
DROP TRIGGER <%= singularized_table_name %>_versions_prevent_update
|
34
|
-
ON <%= singularized_table_name %>_versions;
|
35
|
-
DROP TRIGGER <%= table_name %>_set_hoardable_id
|
36
|
-
ON <%= table_name %>;
|
37
|
-
DROP TRIGGER <%= table_name %>_prevent_update_hoardable_id
|
38
|
-
ON <%= table_name %>;
|
39
|
-
SQL
|
40
|
-
)
|
15
|
+
execute('UPDATE <%= table_name %> SET hoardable_id = <%= primary_key %>;')
|
41
16
|
end
|
42
17
|
end
|
18
|
+
create_trigger(
|
19
|
+
:<%= singularized_table_name %>_versions_prevent_update,
|
20
|
+
on: :<%= singularized_table_name %>_versions
|
21
|
+
)
|
22
|
+
create_trigger :<%= table_name %>_set_hoardable_id, on: :<%= table_name %>
|
23
|
+
create_trigger :<%= table_name %>_prevent_update_hoardable_id, on: :<%= table_name %>
|
43
24
|
change_column_null :<%= table_name %>, :hoardable_id, false
|
44
25
|
add_index :<%= singularized_table_name %>_versions, :<%= primary_key %>, unique: true
|
45
26
|
add_index :<%= singularized_table_name %>_versions, :hoardable_id
|
data/lib/hoardable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hoardable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- justin talbott
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -70,6 +70,26 @@ dependencies:
|
|
70
70
|
- - "<"
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: '8'
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: fx
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0.8'
|
80
|
+
- - "<"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1'
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.8'
|
90
|
+
- - "<"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '1'
|
73
93
|
- !ruby/object:Gem::Dependency
|
74
94
|
name: pg
|
75
95
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,10 +124,16 @@ files:
|
|
104
124
|
- LICENSE.txt
|
105
125
|
- README.md
|
106
126
|
- Rakefile
|
127
|
+
- lib/generators/hoardable/functions/hoardable_prevent_update_id.sql
|
128
|
+
- lib/generators/hoardable/functions/hoardable_source_set_id.sql
|
129
|
+
- lib/generators/hoardable/functions/hoardable_version_prevent_update.sql
|
107
130
|
- lib/generators/hoardable/install_generator.rb
|
108
131
|
- lib/generators/hoardable/migration_generator.rb
|
109
132
|
- lib/generators/hoardable/templates/install.rb.erb
|
110
133
|
- lib/generators/hoardable/templates/migration.rb.erb
|
134
|
+
- lib/generators/hoardable/triggers/prevent_update_hoardable_id.sql
|
135
|
+
- lib/generators/hoardable/triggers/set_hoardable_id.sql
|
136
|
+
- lib/generators/hoardable/triggers/versions_prevent_update.sql
|
111
137
|
- lib/hoardable.rb
|
112
138
|
- lib/hoardable/associations.rb
|
113
139
|
- lib/hoardable/belongs_to.rb
|
@@ -141,14 +167,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
141
167
|
requirements:
|
142
168
|
- - ">="
|
143
169
|
- !ruby/object:Gem::Version
|
144
|
-
version: 2.
|
170
|
+
version: 2.7.0
|
145
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
172
|
requirements:
|
147
173
|
- - ">="
|
148
174
|
- !ruby/object:Gem::Version
|
149
175
|
version: '0'
|
150
176
|
requirements: []
|
151
|
-
rubygems_version: 3.
|
177
|
+
rubygems_version: 3.4.6
|
152
178
|
signing_key:
|
153
179
|
specification_version: 4
|
154
180
|
summary: An ActiveRecord extension for versioning and soft-deletion of records in
|