hoardable 0.13.0 → 0.14.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/.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 
|
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
|