archive_hook 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e54918283bc4fcb9f8c3890c51191fe8b844e0d82d6fe6f5316c2af38a3ebc3e
4
- data.tar.gz: 2126bf291081eb4943422c7ff7ac3fc57ace9faa9904c94904a3ccf780355de6
3
+ metadata.gz: 4952c4f26bb1327189da3753cbf44bf1fcd76f5477cc8e0160265d508b3f46db
4
+ data.tar.gz: 8e0930ef126fef1b8ff7e347a5ba17b95b0aad13eaabc4a1818f918c10edba3c
5
5
  SHA512:
6
- metadata.gz: aba9e9c6ec17d9b92cc90915e48ed451daf3c82aa8cd723a4700b1d1e2da07c504e2374b0c6ca5f8667cae59e69f679c45a851e4fd9c38034c60b0d24d1c4c62
7
- data.tar.gz: 677fcee118a322e088f6c8c66dffd8a9b7468812f3025182bfa4ffa6714cf6635088fe5928dfe788316bc624bc93f7273a6577ce7b6b47f3e459fae4403f9a42
6
+ metadata.gz: 9ea29d7cb8a0269f8a3bd956820d21f69bd33cff1cfc9ca3c8a3c3d7b35fabb0cb2b34362402ee4233f50dd11ea33f72f96f1d57ef3505834da837d793a158a0
7
+ data.tar.gz: b1dcefaf9e2b9e0b6c7caa491756a7876557f2dc0e6ce8bd95070a7f3120a7fa2717370c0dc6a8eda06c510251aeac0080976fd3be4c27e905c22513d11b52ad
@@ -1,3 +1,3 @@
1
1
  module ArchiveHook
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
data/lib/archive_hook.rb CHANGED
@@ -1,7 +1,29 @@
1
1
  require "archive_hook/version"
2
2
 
3
3
  module ArchiveHook
4
+ # Identifiers are interpolated straight into SQL, so anything that needs
5
+ # quoting -- a column called "default", "order" or "group", a table name that
6
+ # collides with a keyword -- has to be quoted or Postgres rejects the
7
+ # statement with a syntax error.
8
+ module Quoting
9
+ private
10
+
11
+ def quote_columns(column_names)
12
+ column_names.map { |name| connection.quote_column_name(name) }.join(",")
13
+ end
14
+
15
+ def quote_table(name)
16
+ connection.quote_table_name(name)
17
+ end
18
+
19
+ def connection
20
+ ActiveRecord::Base.connection
21
+ end
22
+ end
23
+
4
24
  class ScopeArchiver
25
+ include Quoting
26
+
5
27
  def initialize(dependencies: {})
6
28
  @dependencies = dependencies
7
29
  end
@@ -37,23 +59,24 @@ module ArchiveHook
37
59
  end
38
60
 
39
61
  def archive_records_sql(scope)
40
- table_name = scope.table_name
41
- attributes_list = scope.column_names.join(",")
62
+ attributes_list = quote_columns(scope.column_names)
42
63
  <<-SQL
43
- INSERT INTO #{table_name}_archive (#{attributes_list})
64
+ INSERT INTO #{quote_table("#{scope.table_name}_archive")} (#{attributes_list})
44
65
  #{scope.select(attributes_list).to_sql}
45
66
  SQL
46
67
  end
47
68
  end
48
69
 
49
70
  class ScopeRestorer
71
+ include Quoting
72
+
50
73
  def initialize(dependencies: {})
51
74
  @dependencies = dependencies
52
75
  end
53
76
 
54
77
  def call(scope)
55
78
  parent = scope.model
56
- table_name = "#{scope.table_name}_archive as #{scope.table_name}"
79
+ table_name = "#{quote_table("#{scope.table_name}_archive")} as #{quote_table(scope.table_name)}"
57
80
  parent_id_groups = scope.from(table_name).in_batches.map { |relation| relation.pluck(:id) }
58
81
  parent_id_groups.each do |parent_ids|
59
82
  restore_by_ids(parent, parent_ids)
@@ -78,22 +101,22 @@ module ArchiveHook
78
101
  end
79
102
 
80
103
  def restore_by_ids(model, ids)
81
- table_name = model.table_name
82
104
  ActiveRecord::Base.transaction do
83
- ActiveRecord::Base.connection.execute(Arel.sql(restore_records_sql(model, ids)))
84
- ActiveRecord::Base.connection.execute(Arel.sql <<-SQL
85
- DELETE FROM #{table_name}_archive WHERE id IN (#{ids.join(', ')})
105
+ connection.execute(Arel.sql(restore_records_sql(model, ids)))
106
+ connection.execute(Arel.sql <<-SQL
107
+ DELETE FROM #{quote_table("#{model.table_name}_archive")}
108
+ WHERE #{connection.quote_column_name(model.primary_key)} IN (#{ids.join(', ')})
86
109
  SQL
87
110
  )
88
111
  end
89
112
  end
90
113
 
91
114
  def restore_records_sql(model, ids)
92
- table_name = model.table_name
93
- attributes_list = model.column_names.join(",")
115
+ attributes_list = quote_columns(model.column_names)
94
116
  <<-SQL
95
- INSERT INTO #{table_name} (#{attributes_list})
96
- SELECT #{attributes_list} FROM #{table_name}_archive WHERE id IN (#{ids.join(', ')})
117
+ INSERT INTO #{quote_table(model.table_name)} (#{attributes_list})
118
+ SELECT #{attributes_list} FROM #{quote_table("#{model.table_name}_archive")}
119
+ WHERE #{connection.quote_column_name(model.primary_key)} IN (#{ids.join(', ')})
97
120
  SQL
98
121
  end
99
122
  end
@@ -101,7 +124,8 @@ module ArchiveHook
101
124
  class << self
102
125
  def archive(root, archive_date, dependencies)
103
126
  column = dependencies[root] && dependencies[root][:column] || :created_at
104
- base_scope = root.where("#{column} < ?", archive_date)
127
+ quoted_column = ActiveRecord::Base.connection.quote_column_name(column)
128
+ base_scope = root.where("#{quoted_column} < ?", archive_date)
105
129
  ScopeArchiver.new(dependencies: dependencies).call(base_scope)
106
130
  end
107
131
 
@@ -2,7 +2,13 @@
2
2
 
3
3
  class Create<%= archive_table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
4
  def up
5
- execute("CREATE TABLE <%= archive_table_name %> (LIKE <%= table_name %>)")
5
+ # Quoted at run time so a mixed-case table name survives Postgres folding
6
+ # unquoted identifiers to lower case, and so a name that collides with a
7
+ # reserved word still parses.
8
+ execute(
9
+ "CREATE TABLE #{connection.quote_table_name('<%= archive_table_name %>')} " \
10
+ "(LIKE #{connection.quote_table_name('<%= table_name %>')})"
11
+ )
6
12
  end
7
13
 
8
14
  def down
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: archive_hook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - alvir
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-31 00:00:00.000000000 Z
11
+ date: 2026-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord