archival_record 3.0.1 → 4.0.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/.envrc +9 -0
- data/.gitignore +1 -1
- data/.rubocop.yml +1 -1
- data/Appraisals +14 -0
- data/CHANGELOG.md +12 -2
- data/Gemfile.lock +67 -47
- data/LICENSE +1 -1
- data/README.md +61 -29
- data/archival_record.gemspec +4 -2
- data/gemfiles/rails_6.0.gemfile +2 -0
- data/gemfiles/rails_6.1.gemfile +2 -0
- data/gemfiles/rails_7.0.gemfile +2 -0
- data/gemfiles/rails_7.2.gemfile +7 -0
- data/gemfiles/rails_8.0.gemfile +7 -0
- data/lib/archival_record/version.rb +1 -1
- data/lib/archival_record.rb +2 -9
- data/lib/archival_record_core/archival_record.rb +14 -5
- data/lib/archival_record_core/archival_record_active_record_methods.rb +1 -3
- data/lib/archival_record_core/association_operation/archive.rb +0 -4
- data/lib/archival_record_core/association_operation/base.rb +25 -2
- data/shell.nix +41 -0
- data/test/associations_test.rb +22 -2
- data/test/bogus_relation_test.rb +2 -2
- data/test/callbacks_test.rb +14 -33
- data/test/exception_test.rb +9 -0
- data/test/fixtures/another_polys_holder.rb +1 -1
- data/test/fixtures/archival.rb +13 -7
- data/test/fixtures/archival_grandkid.rb +1 -1
- data/test/fixtures/archival_kid.rb +1 -1
- data/test/fixtures/archival_table_name.rb +1 -1
- data/test/fixtures/callback_archival.rb +13 -16
- data/test/fixtures/deprecated_warning_archival.rb +1 -1
- data/test/fixtures/exception_raiser.rb +11 -0
- data/test/fixtures/explicit_act_on_dependents_archival.rb +1 -1
- data/test/fixtures/exploder.rb +1 -1
- data/test/fixtures/ignorable_dependent.rb +1 -1
- data/test/fixtures/ignore_dependents_archival.rb +1 -1
- data/test/fixtures/independent_archival.rb +1 -1
- data/test/fixtures/many_many_archival.rb +9 -0
- data/test/fixtures/missing_archive_number.rb +1 -1
- data/test/fixtures/missing_archived_at.rb +1 -1
- data/test/fixtures/nonignorable_dependent.rb +1 -1
- data/test/fixtures/plain.rb +1 -1
- data/test/fixtures/poly.rb +1 -1
- data/test/fixtures/readonly_when_archived.rb +1 -1
- data/test/performance/the_test.rb +29 -0
- data/test/schema.rb +14 -12
- data/test/scope_test.rb +2 -2
- data/test/test_helper.rb +19 -5
- metadata +44 -11
- data/.gitlab-ci.yml +0 -20
- data/test/application_record_test.rb +0 -20
- data/test/fixtures/application_record_row.rb +0 -8
- /data/test/{fixtures/application_record.rb → application_record.rb} +0 -0
@@ -3,6 +3,21 @@ module ArchivalRecordCore
|
|
3
3
|
module AssociationOperation
|
4
4
|
class Base
|
5
5
|
|
6
|
+
ACTIVE_RECORD_REQUIREMENT_DESTROY_ASYNC = Gem::Requirement.new(">= 6.1.0")
|
7
|
+
|
8
|
+
# :destroy_async was added as an option in rails 6.1 but seems very buggy there
|
9
|
+
# wrt to configuration
|
10
|
+
DEPENDENT_OPTIONS_TO_OPERATE_ON_RAILS_6_0 = %i[
|
11
|
+
destroy
|
12
|
+
delete_all
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
DEPENDENT_OPTIONS_TO_OPERATE_ON_RAILS = %i[
|
16
|
+
destroy
|
17
|
+
destroy_async
|
18
|
+
delete_all
|
19
|
+
].freeze
|
20
|
+
|
6
21
|
attr_reader :model, :head_archive_number
|
7
22
|
|
8
23
|
def initialize(model, head_archive_number)
|
@@ -32,8 +47,16 @@ module ArchivalRecordCore
|
|
32
47
|
association.options[:through].nil?
|
33
48
|
end
|
34
49
|
|
35
|
-
def
|
36
|
-
|
50
|
+
def dependent_options_to_operate_on
|
51
|
+
if ACTIVE_RECORD_REQUIREMENT_DESTROY_ASYNC.satisfied_by?(ActiveRecord.version)
|
52
|
+
DEPENDENT_OPTIONS_TO_OPERATE_ON_RAILS
|
53
|
+
else
|
54
|
+
DEPENDENT_OPTIONS_TO_OPERATE_ON_RAILS_6_0
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def association_conditions_met?(association)
|
59
|
+
dependent_options_to_operate_on.include?(association.options[:dependent])
|
37
60
|
end
|
38
61
|
|
39
62
|
def act_on_association(association)
|
data/shell.nix
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
lib ? import <lib> {},
|
3
|
+
pkgs ? import (fetchTarball channel:nixos-24.11) {}
|
4
|
+
}:
|
5
|
+
|
6
|
+
let
|
7
|
+
|
8
|
+
# define packages to install with special handling for OSX
|
9
|
+
basePackages = [
|
10
|
+
pkgs.gnumake
|
11
|
+
pkgs.gcc
|
12
|
+
pkgs.readline
|
13
|
+
pkgs.zlib
|
14
|
+
pkgs.libxml2
|
15
|
+
pkgs.libiconv
|
16
|
+
pkgs.libffi
|
17
|
+
pkgs.openssl
|
18
|
+
pkgs.curl
|
19
|
+
pkgs.git
|
20
|
+
|
21
|
+
pkgs.sqlite
|
22
|
+
|
23
|
+
pkgs.ruby_3_2
|
24
|
+
pkgs.bundler
|
25
|
+
];
|
26
|
+
|
27
|
+
inputs = basePackages
|
28
|
+
++ [ pkgs.bashInteractive ]
|
29
|
+
++ pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.inotify-tools ]
|
30
|
+
++ pkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [
|
31
|
+
CoreFoundation
|
32
|
+
CoreServices
|
33
|
+
]);
|
34
|
+
|
35
|
+
in pkgs.mkShell {
|
36
|
+
buildInputs = inputs;
|
37
|
+
|
38
|
+
shellHook = ''
|
39
|
+
export APP_HOME=$(pwd);
|
40
|
+
'';
|
41
|
+
}
|
data/test/associations_test.rb
CHANGED
@@ -11,6 +11,26 @@ class AssociationsTest < ActiveSupport::TestCase
|
|
11
11
|
assert child.reload.archived?
|
12
12
|
end
|
13
13
|
|
14
|
+
if ActiveRecord.version >= Gem::Version.new("6.1.0")
|
15
|
+
test "archive archives 'has_' associated archival objects that are dependent destroy_async" do
|
16
|
+
archival = Archival.create!
|
17
|
+
child = archival.archivals_destroy_async.create!
|
18
|
+
archival.archive!
|
19
|
+
|
20
|
+
assert archival.reload.archived?
|
21
|
+
assert child.reload.archived?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
test "archive archives 'has_' associated archival objects that are dependent delete_all" do
|
26
|
+
archival = Archival.create!
|
27
|
+
child = archival.archivals_delete.create!
|
28
|
+
archival.archive!
|
29
|
+
|
30
|
+
assert archival.reload.archived?
|
31
|
+
assert child.reload.archived?
|
32
|
+
end
|
33
|
+
|
14
34
|
test "archive acts on all objects in the 'has_' relationship" do
|
15
35
|
archival = Archival.create!
|
16
36
|
children = [archival.archivals.create!, archival.archivals.create!]
|
@@ -81,7 +101,7 @@ class AssociationsTest < ActiveSupport::TestCase
|
|
81
101
|
assert prearchived_child.reload.archived?
|
82
102
|
end
|
83
103
|
|
84
|
-
test "unarchive
|
104
|
+
test "unarchive does not act on 'has_' associated non-dependent_destroy objects" do
|
85
105
|
archival = Archival.create!
|
86
106
|
independent = archival.independent_archivals.create!
|
87
107
|
archival.archive!
|
@@ -89,7 +109,7 @@ class AssociationsTest < ActiveSupport::TestCase
|
|
89
109
|
archival.unarchive!
|
90
110
|
|
91
111
|
assert_not archival.reload.archived?
|
92
|
-
|
112
|
+
assert independent.reload.archived?
|
93
113
|
end
|
94
114
|
|
95
115
|
test "unarchive doesn't unarchive associated objects if the head object is already unarchived" do
|
data/test/bogus_relation_test.rb
CHANGED
@@ -4,10 +4,10 @@ class BogusRelationTest < ActiveSupport::TestCase
|
|
4
4
|
|
5
5
|
test "does not successfully archive" do
|
6
6
|
archival = BogusRelation.create!
|
7
|
-
stub(
|
7
|
+
stub(ApplicationRecord.logger).error(
|
8
8
|
satisfy do |arg|
|
9
9
|
if arg.is_a?(String)
|
10
|
-
arg
|
10
|
+
arg.match?(/\ASQLite3::SQLException: no such column: bogus_relations.bogus_relation_id/)
|
11
11
|
elsif arg.is_a?(Array)
|
12
12
|
arg.join.match?(%r{gems/activerecord}) # this is gonna be in the stack trace somewhere
|
13
13
|
else
|
data/test/callbacks_test.rb
CHANGED
@@ -2,40 +2,21 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
class CallbacksTest < ActiveSupport::TestCase
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
test "can be halted" do
|
15
|
-
archival = CallbackArchival5.create
|
16
|
-
archival.set_this_value = "a test string"
|
17
|
-
archival.pass_callback = false
|
18
|
-
assert_nil archival.settable_field
|
19
|
-
archival.archive!
|
20
|
-
assert_nil archival.reload.settable_field
|
21
|
-
end
|
22
|
-
else
|
23
|
-
test "can set a value as part of archiving" do
|
24
|
-
archival = CallbackArchival4.create
|
25
|
-
archival.set_this_value = "a test string"
|
26
|
-
assert_nil archival.settable_field
|
27
|
-
archival.archive!
|
28
|
-
assert_equal "a test string", archival.reload.settable_field
|
29
|
-
end
|
5
|
+
test "can set a value as part of archiving" do
|
6
|
+
archival = CallbackArchival.create
|
7
|
+
archival.set_this_value = "a test string"
|
8
|
+
assert_nil archival.settable_field
|
9
|
+
archival.archive!
|
10
|
+
assert_equal "a test string", archival.reload.settable_field
|
11
|
+
end
|
30
12
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
13
|
+
test "can be halted" do
|
14
|
+
archival = CallbackArchival.create
|
15
|
+
archival.set_this_value = "a test string"
|
16
|
+
archival.pass_callback = false
|
17
|
+
assert_nil archival.settable_field
|
18
|
+
archival.archive!
|
19
|
+
assert_nil archival.reload.settable_field
|
39
20
|
end
|
40
21
|
|
41
22
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class ExceptionTest < ActiveSupport::TestCase
|
2
|
+
|
3
|
+
test "raises an exception when given that option" do
|
4
|
+
readonly = ExceptionRaiser.create!(archived_at: Time.now.utc, archive_number: "1")
|
5
|
+
readonly.readonly!
|
6
|
+
assert_raises(ActiveRecord::ReadOnlyRecord) { readonly.unarchive! }
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
data/test/fixtures/archival.rb
CHANGED
@@ -2,18 +2,24 @@
|
|
2
2
|
# archival_id - integer
|
3
3
|
# archive_number - string
|
4
4
|
# archived_at - datetime
|
5
|
-
class Archival <
|
5
|
+
class Archival < ApplicationRecord
|
6
6
|
|
7
7
|
archival_record
|
8
8
|
|
9
|
-
has_many :archivals,
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
has_many :
|
14
|
-
has_many :
|
9
|
+
has_many :archivals, dependent: :destroy
|
10
|
+
if ActiveRecord.version >= Gem::Version.new("6.1.0")
|
11
|
+
has_many :archivals_destroy_async, dependent: :destroy_async, class_name: "Archival"
|
12
|
+
end
|
13
|
+
has_many :archivals_delete, dependent: :delete_all, class_name: "Archival"
|
14
|
+
has_many :archival_kids, dependent: :destroy
|
15
|
+
has_many :archival_grandkids, dependent: :destroy, through: :archival_kids
|
16
|
+
has_many :exploders, dependent: :destroy
|
17
|
+
has_many :plains, dependent: :destroy
|
18
|
+
has_many :polys, dependent: :destroy, as: :archiveable
|
15
19
|
has_many :independent_archivals
|
16
20
|
|
21
|
+
has_and_belongs_to_many :many_many_archivals
|
22
|
+
|
17
23
|
scope :bobs, -> { where(name: %w[Bob Bobby Robert]) }
|
18
24
|
|
19
25
|
end
|
@@ -1,23 +1,20 @@
|
|
1
|
-
|
2
|
-
if defined?(ApplicationRecord)
|
3
|
-
class CallbackArchival5 < ApplicationRecord
|
1
|
+
class CallbackArchival < ApplicationRecord
|
4
2
|
|
5
|
-
|
3
|
+
archival_record
|
6
4
|
|
7
|
-
|
8
|
-
|
5
|
+
attr_accessor :set_this_value,
|
6
|
+
:pass_callback
|
9
7
|
|
10
|
-
|
11
|
-
|
8
|
+
before_archive :set_value,
|
9
|
+
:conditional_callback_passer
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
private def conditional_callback_passer
|
18
|
-
# we want to throw only for the value false
|
19
|
-
throw(:abort) unless pass_callback || pass_callback.nil?
|
20
|
-
end
|
11
|
+
private def set_value
|
12
|
+
self.settable_field = set_this_value
|
13
|
+
end
|
21
14
|
|
15
|
+
private def conditional_callback_passer
|
16
|
+
# we want to throw only for the value false
|
17
|
+
throw(:abort) unless pass_callback || pass_callback.nil?
|
22
18
|
end
|
19
|
+
|
23
20
|
end
|
data/test/fixtures/exploder.rb
CHANGED
data/test/fixtures/plain.rb
CHANGED
data/test/fixtures/poly.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
module Performance
|
4
|
+
class TheTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
### What is this?
|
7
|
+
### Well currently it's a testing harness for checking indices but it's useful to have a
|
8
|
+
### test to check things out. And this is that.
|
9
|
+
|
10
|
+
# test "performance tester" do
|
11
|
+
# puts "please hold, we are making ~10K records"
|
12
|
+
|
13
|
+
# percent_to_archive = 20
|
14
|
+
# records_to_make = 10_000
|
15
|
+
|
16
|
+
# records_to_make.times do
|
17
|
+
# archival = Archival.create!
|
18
|
+
# archival.archive! if rand(100) <= percent_to_archive
|
19
|
+
# end
|
20
|
+
|
21
|
+
# # Archival.archived.explain
|
22
|
+
# # Archival.unarchived.explain
|
23
|
+
# # binding.pry
|
24
|
+
|
25
|
+
# assert "we did it"
|
26
|
+
# end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/test/schema.rb
CHANGED
@@ -13,6 +13,9 @@ ActiveRecord::Schema.define(version: 1) do
|
|
13
13
|
t.column :archived_at, :datetime
|
14
14
|
end
|
15
15
|
|
16
|
+
add_index(:archivals, :archive_number)
|
17
|
+
add_index(:archivals, :archived_at)
|
18
|
+
|
16
19
|
create_table :exploders, force: true do |t|
|
17
20
|
t.column :archival_id, :integer
|
18
21
|
t.column :archive_number, :string
|
@@ -71,18 +74,7 @@ ActiveRecord::Schema.define(version: 1) do
|
|
71
74
|
t.column :archived_at, :datetime
|
72
75
|
end
|
73
76
|
|
74
|
-
create_table :
|
75
|
-
t.column :archive_number, :string
|
76
|
-
t.column :archived_at, :datetime
|
77
|
-
end
|
78
|
-
|
79
|
-
create_table :callback_archival4s, force: true do |t|
|
80
|
-
t.column :settable_field, :string
|
81
|
-
t.column :archive_number, :string
|
82
|
-
t.column :archived_at, :datetime
|
83
|
-
end
|
84
|
-
|
85
|
-
create_table :callback_archival5s, force: true do |t|
|
77
|
+
create_table :callback_archivals, force: true do |t|
|
86
78
|
t.column :settable_field, :string
|
87
79
|
t.column :archive_number, :string
|
88
80
|
t.column :archived_at, :datetime
|
@@ -120,4 +112,14 @@ ActiveRecord::Schema.define(version: 1) do
|
|
120
112
|
t.column :archive_number, :string
|
121
113
|
t.column :archived_at, :datetime
|
122
114
|
end
|
115
|
+
|
116
|
+
create_table :many_many_archivals, force: true do |t|
|
117
|
+
t.column :archive_number, :string
|
118
|
+
t.column :archived_at, :datetime
|
119
|
+
end
|
120
|
+
|
121
|
+
create_table :archivals_many_many_archivals, force: true do |t|
|
122
|
+
t.column :archival_id, :integer
|
123
|
+
t.column :many_many_archival_id, :integer
|
124
|
+
end
|
123
125
|
end
|
data/test/scope_test.rb
CHANGED
@@ -51,9 +51,9 @@ class ScopeTest < ActiveSupport::TestCase
|
|
51
51
|
|
52
52
|
test "table_name is set to 'legacy'" do
|
53
53
|
archived_sql = 'SELECT "legacy".* FROM "legacy" ' \
|
54
|
-
'WHERE "legacy"."
|
54
|
+
'WHERE "legacy"."archive_number" IS NOT NULL'
|
55
55
|
unarchived_sql = 'SELECT "legacy".* FROM "legacy" ' \
|
56
|
-
'WHERE "legacy"."
|
56
|
+
'WHERE "legacy"."archive_number" IS NULL'
|
57
57
|
assert_equal archived_sql, ArchivalTableName.archived.to_sql
|
58
58
|
assert_equal unarchived_sql, ArchivalTableName.unarchived.to_sql
|
59
59
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib")
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
|
+
# you might be tempted to alphabetize this list of requires, but you should not.
|
5
|
+
# and logger definitely needs to go first or nearly first.
|
6
|
+
require "logger"
|
7
|
+
|
4
8
|
require "minitest/autorun"
|
5
9
|
require "minitest/pride"
|
10
|
+
require "pry"
|
6
11
|
|
12
|
+
require "active_job"
|
7
13
|
require "active_record"
|
14
|
+
require_relative "application_record"
|
8
15
|
require "database_cleaner"
|
9
16
|
|
10
17
|
require "archival_record"
|
@@ -12,6 +19,7 @@ require "archival_record"
|
|
12
19
|
ActiveSupport::TestCase.test_order = :random if ActiveSupport::TestCase.respond_to?(:test_order=)
|
13
20
|
|
14
21
|
def prepare_for_tests
|
22
|
+
setup_active_job if ActiveRecord.version >= Gem::Version.new("6.1.0")
|
15
23
|
setup_logging
|
16
24
|
setup_database_cleaner
|
17
25
|
create_test_tables
|
@@ -19,9 +27,15 @@ def prepare_for_tests
|
|
19
27
|
end
|
20
28
|
|
21
29
|
def setup_logging
|
22
|
-
|
30
|
+
return if ENV["AR_LOGGER"] != "1"
|
31
|
+
|
23
32
|
logfile = "#{File.dirname(__FILE__)}/debug.log"
|
24
|
-
|
33
|
+
ApplicationRecord.logger = Logger.new(logfile)
|
34
|
+
end
|
35
|
+
|
36
|
+
def setup_active_job
|
37
|
+
# usually rails does this for you but we don't have rails do we
|
38
|
+
ActiveRecord::Base.destroy_association_async_job = ActiveRecord::DestroyAssociationAsyncJob
|
25
39
|
end
|
26
40
|
|
27
41
|
def setup_database_cleaner
|
@@ -46,14 +60,12 @@ end
|
|
46
60
|
|
47
61
|
def create_test_tables
|
48
62
|
puts "** Loading schema for SQLite"
|
49
|
-
|
63
|
+
ApplicationRecord.establish_connection(sqlite_config)
|
50
64
|
load(schema_file) if File.exist?(schema_file)
|
51
65
|
end
|
52
66
|
|
53
67
|
FIXTURE_CLASSES = %I[
|
54
68
|
another_polys_holder
|
55
|
-
application_record
|
56
|
-
application_record_row
|
57
69
|
archival
|
58
70
|
archival_grandkid
|
59
71
|
archival_kid
|
@@ -61,11 +73,13 @@ FIXTURE_CLASSES = %I[
|
|
61
73
|
bogus_relation
|
62
74
|
callback_archival
|
63
75
|
deprecated_warning_archival
|
76
|
+
exception_raiser
|
64
77
|
explicit_act_on_dependents_archival
|
65
78
|
exploder
|
66
79
|
ignorable_dependent
|
67
80
|
ignore_dependents_archival
|
68
81
|
independent_archival
|
82
|
+
many_many_archival
|
69
83
|
missing_archive_number
|
70
84
|
missing_archived_at
|
71
85
|
nonignorable_dependent
|