logidze 1.2.3 → 1.3.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: ac315542fe9ec1866a4395ed04f1e431d65fe6c9dfc72874a423224c0b52b3cb
4
- data.tar.gz: deb4efcba8179273185738fbe395458f6bd4165bf8ed1263b0348bf9bc4b45ab
3
+ metadata.gz: c4ab83a61c2685b93d8fe58199eac1fb889c4459453db9315bd6a9880abb2bc9
4
+ data.tar.gz: f856bd257d81c6ad1fc3cbe6328bbd1adbf77670335a07a0f5234f572f8a7145
5
5
  SHA512:
6
- metadata.gz: bffd04a3005c169a56e3280eaceb7c22623b7d7cfdf82719d65f16804fd86adee32f9afdccd6e767923dd5f6b0b63c0354455ad5daba7a608a420190cae4c2fd
7
- data.tar.gz: c7296b56fed241dc7f55a16a5307b596f1ec016f334cb743c47272295db3ee4d1236bbda0f97c78a9b4a8e50309e07757322611c41bb5386bdbee3500fa57a1b
6
+ metadata.gz: d462f59ba20d402c5c75bb15ea40b709f278088dcd11be7e769640640450bd35a558794884fca89ccdaa403e09fb0d05c40d43bed8dd86698a41ecb870272a4b
7
+ data.tar.gz: f5bf80de51ffaff0f611e84bbf99f4291ebb82655ff23ce555d042c3ae29f3d79c172e1b7de7c1f19083892a847473ce6252364973e31eecb41d25fe8e1de65b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
+ ## 1.3.0 (2024-01-09)
6
+
7
+ - Add retrieving list of versions support. ([@tagirahmad][])
8
+
9
+ ```ruby
10
+ post.versions # => Enumerator
11
+ post.versions.find do
12
+ _1.title == "old title"
13
+ end
14
+ ```
15
+
16
+ - Add `--after-trigger` option to generate _after_ triggers for partitioned tables in older PostgreSQL versions. ([@SparLaimor][], [@prog-supdex][], [@palkan][])
17
+
18
+ - **Breaking**. Ruby 2.7, Rails 6.0, PostgreSQL 10.0+ are required.
19
+
5
20
  ## 1.2.3 (2023-01-03)
6
21
 
7
22
  - [Fixes [#217](https://github.com/palkan/logidze/issues/217)] Fix switch_to with `append: true` when there are changes on JSONB columns. ([@miharekar][])
@@ -376,3 +391,7 @@ This is a quick fix for a more general problem (see [#59](https://github.com/pal
376
391
  [@cavi21]: https://github.com/cavi21
377
392
  [@danielmklein]: https://github.com/danielmklein
378
393
  [@baygeldin]: https://github.com/baygeldin
394
+ [@miharekar]: https://github.com/miharekar
395
+ [@prog-supdex]: https://github.com/prog-supdex
396
+ [@SparLaimor]: https://github.com/SparLaimor
397
+ [@tagirahmad]: https://github.com/tagirahmad
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  # Logidze
7
7
 
8
- Logidze provides tools for logging DB records changes when using PostgreSQL (>=9.6). Just like [audited](https://github.com/collectiveidea/audited) and [paper_trail](https://github.com/airblade/paper_trail) do (but [faster](bench/performance)).
8
+ Logidze provides tools for logging DB records changes when using PostgreSQL. Just like [audited](https://github.com/collectiveidea/audited) and [paper_trail](https://github.com/airblade/paper_trail) do (but [faster](bench/performance)).
9
9
 
10
10
  Logidze allows you to create a DB-level log (using triggers) and gives you an API to browse this log.
11
11
  The log is stored with the record itself in JSONB column. No additional tables required.
@@ -14,8 +14,9 @@ The log is stored with the record itself in JSONB column. No additional tables r
14
14
 
15
15
  Other requirements:
16
16
 
17
- - Ruby ~> 2.5
18
- - Rails >= 5.0 (for Rails 4.2 use version <=0.12.0)
17
+ - Ruby ~> 2.7
18
+ - Rails >= 6.0 (for Rails 4.2 use version <=0.12.0, for Rails 5.x use version <= 1.2.3)
19
+ - PostgreSQL >= 10.0
19
20
 
20
21
  <a href="https://evilmartians.com/">
21
22
  <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
@@ -35,6 +36,7 @@ Other requirements:
35
36
  - [Tracking only selected columns](#tracking-only-selected-columns)
36
37
  - [Logs timestamps](#logs-timestamps)
37
38
  - [Undoing a Generated Invocation](#undoing-a-generated-invocation)
39
+ - [Using with partitioned tables](#using-with-partitioned-tables)
38
40
  - [Usage](#usage)
39
41
  - [Basic API](#basic-api)
40
42
  - [Track meta information](#track-meta-information)
@@ -189,6 +191,18 @@ bundle exec rails destroy logidze:model Post
189
191
 
190
192
  **IMPORTANT**: If you use non-UTC time zone for Active Record (`config.active_record.default_timezone`), you MUST always infer log timestamps from a timestamp column (e.g., when back-filling data); otherwise, you may end up with inconsistent logs ([#199](https://github.com/palkan/logidze/issues/199)). In general, we recommend using UTC as the database time unless there is a very strong reason not to.
191
193
 
194
+ ### Using with partitioned tables
195
+
196
+ Logidze supports partitioned tables for PostgreSQL 13+ without any additional configuration. For PostgreSQL 11/12, you should use _after_ triggers. To do that, provide the `--after-trigger` option to the migration:
197
+
198
+ ```sh
199
+ bundle exec rails generate logidze:model Post --after-trigger
200
+ ```
201
+
202
+ **NOTE:** Record changes are written as a full snapshot if the partition has changed during the update.
203
+
204
+ **IMPORTANT:** Using Logidze for partitioned tables in PostgreSQL 10 is not supported.
205
+
192
206
  ## Usage
193
207
 
194
208
  ### Basic API
@@ -243,6 +257,25 @@ Post.where(created_at: Time.zone.today.all_day).diff_from(time: 1.hour.ago)
243
257
 
244
258
  **NOTE:** If `log_data` is nil, `#diff_from` returns an empty Hash as `"changes"`.
245
259
 
260
+ Also, it is possible to retrieve list of model's `versions`:
261
+
262
+ ```ruby
263
+ post.versions # => Enumerator
264
+
265
+ # you can use Enumerator's #take to return all
266
+ post.versions.take
267
+
268
+ # or you take a few or call any Enumerable method
269
+ post.versions.take(2)
270
+ post.versions.find do
271
+ _1.title == "old title"
272
+ end
273
+
274
+ # we can also add options
275
+ post.versions(reverse: true) # from older to newer
276
+ post.versions(include_self: true) # returns self as the first one (default) or the last one record (if reverse: true)
277
+ ```
278
+
246
279
  There are also `#undo!` and `#redo!` options (and more general `#switch_to!`):
247
280
 
248
281
  ```ruby
@@ -302,6 +335,10 @@ Logidze.with_meta({ip: request.ip}, transactional: false) do
302
335
  end
303
336
  ```
304
337
 
338
+ **Important:** If you use connection pooling (e.g., PgBouncer), using `.with_meta` without a transaction may lead to unexpected results (since meta is set for a connection). Without a transaction, we cannot guarantee that the same connection will be used for queries (including metadata cleanup).
339
+
340
+ **Important**: In Rails, `after_commit` callbacks are executed after transaction is committed, and, thus, after `with_meta` block is executed—the meta wouldn't be added to changes captured in the `after_commit` phase. One particular scenario is having associations with `touch: true` (_touch_ updates are executed after commit).
341
+
305
342
  ### Track responsibility
306
343
 
307
344
  A special application of meta information is storing the author of the change, which is called _Responsible ID_. There is more likely that you would like to store the `current_user.id` that way.
@@ -6,7 +6,7 @@ module Logidze
6
6
  module FxHelper
7
7
  def self.included(base)
8
8
  base.class_option :fx, type: :boolean, optional: true,
9
- desc: "Define whether to use fx gem functionality"
9
+ desc: "Define whether to use fx gem functionality"
10
10
  end
11
11
 
12
12
  def fx?
@@ -1,9 +1,10 @@
1
1
  CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
2
- -- version: 3
2
+ -- version: 4
3
3
  DECLARE
4
4
  changes jsonb;
5
5
  version jsonb;
6
- snapshot jsonb;
6
+ full_snapshot boolean;
7
+ log_data jsonb;
7
8
  new_v integer;
8
9
  size integer;
9
10
  history_limit integer;
@@ -30,59 +31,56 @@ CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
30
31
  columns := NULLIF(TG_ARGV[2], 'null');
31
32
  include_columns := NULLIF(TG_ARGV[3], 'null');
32
33
 
33
- IF TG_OP = 'INSERT' THEN
34
+ IF NEW.log_data is NULL OR NEW.log_data = '{}'::jsonb
35
+ THEN
34
36
  IF columns IS NOT NULL THEN
35
- snapshot = logidze_snapshot(to_jsonb(NEW.*), ts_column, columns, include_columns);
37
+ log_data = logidze_snapshot(to_jsonb(NEW.*), ts_column, columns, include_columns);
36
38
  ELSE
37
- snapshot = logidze_snapshot(to_jsonb(NEW.*), ts_column);
39
+ log_data = logidze_snapshot(to_jsonb(NEW.*), ts_column);
38
40
  END IF;
39
41
 
40
- IF snapshot#>>'{h, -1, c}' != '{}' THEN
41
- NEW.log_data := snapshot;
42
+ IF log_data#>>'{h, -1, c}' != '{}' THEN
43
+ NEW.log_data := log_data;
42
44
  END IF;
43
45
 
44
- ELSIF TG_OP = 'UPDATE' THEN
46
+ ELSE
45
47
 
46
- IF OLD.log_data is NULL OR OLD.log_data = '{}'::jsonb THEN
47
- IF columns IS NOT NULL THEN
48
- snapshot = logidze_snapshot(to_jsonb(NEW.*), ts_column, columns, include_columns);
49
- ELSE
50
- snapshot = logidze_snapshot(to_jsonb(NEW.*), ts_column);
51
- END IF;
52
-
53
- IF snapshot#>>'{h, -1, c}' != '{}' THEN
54
- NEW.log_data := snapshot;
55
- END IF;
56
- RETURN NEW;
48
+ IF TG_OP = 'UPDATE' AND (to_jsonb(NEW.*) = to_jsonb(OLD.*)) THEN
49
+ RETURN NEW; -- pass
57
50
  END IF;
58
51
 
59
52
  history_limit := NULLIF(TG_ARGV[0], 'null');
60
53
  debounce_time := NULLIF(TG_ARGV[4], 'null');
61
54
 
62
- current_version := (NEW.log_data->>'v')::int;
55
+ log_data := NEW.log_data;
56
+
57
+ current_version := (log_data->>'v')::int;
63
58
 
64
59
  IF ts_column IS NULL THEN
65
60
  ts := statement_timestamp();
66
- ELSE
67
- ts := (to_jsonb(NEW.*)->>ts_column)::timestamp with time zone;
68
- IF ts IS NULL OR ts = (to_jsonb(OLD.*)->>ts_column)::timestamp with time zone THEN
61
+ ELSEIF TG_OP = 'UPDATE' THEN
62
+ ts := (to_jsonb(NEW.*) ->> ts_column)::timestamp with time zone;
63
+ IF ts IS NULL OR ts = (to_jsonb(OLD.*) ->> ts_column)::timestamp with time zone THEN
64
+ ts := statement_timestamp();
65
+ END IF;
66
+ ELSEIF TG_OP = 'INSERT' THEN
67
+ ts := (to_jsonb(NEW.*) ->> ts_column)::timestamp with time zone;
68
+ IF ts IS NULL OR (extract(epoch from ts) * 1000)::bigint = (NEW.log_data #>> '{h,-1,ts}')::bigint THEN
69
69
  ts := statement_timestamp();
70
70
  END IF;
71
71
  END IF;
72
72
 
73
- IF to_jsonb(NEW.*) = to_jsonb(OLD.*) THEN
74
- RETURN NEW;
75
- END IF;
73
+ full_snapshot := (coalesce(current_setting('logidze.full_snapshot', true), '') = 'on') OR (TG_OP = 'INSERT');
76
74
 
77
- IF current_version < (NEW.log_data#>>'{h,-1,v}')::int THEN
75
+ IF current_version < (log_data#>>'{h,-1,v}')::int THEN
78
76
  iterator := 0;
79
- FOR item in SELECT * FROM jsonb_array_elements(NEW.log_data->'h')
77
+ FOR item in SELECT * FROM jsonb_array_elements(log_data->'h')
80
78
  LOOP
81
79
  IF (item.value->>'v')::int > current_version THEN
82
- NEW.log_data := jsonb_set(
83
- NEW.log_data,
80
+ log_data := jsonb_set(
81
+ log_data,
84
82
  '{h}',
85
- (NEW.log_data->'h') - iterator
83
+ (log_data->'h') - iterator
86
84
  );
87
85
  END IF;
88
86
  iterator := iterator + 1;
@@ -91,7 +89,7 @@ CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
91
89
 
92
90
  changes := '{}';
93
91
 
94
- IF (coalesce(current_setting('logidze.full_snapshot', true), '') = 'on') THEN
92
+ IF full_snapshot THEN
95
93
  BEGIN
96
94
  changes = hstore_to_jsonb_loose(hstore(NEW.*));
97
95
  EXCEPTION
@@ -132,48 +130,50 @@ CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
132
130
  END IF;
133
131
 
134
132
  IF changes = '{}' THEN
135
- RETURN NEW;
133
+ RETURN NEW; -- pass
136
134
  END IF;
137
135
 
138
- new_v := (NEW.log_data#>>'{h,-1,v}')::int + 1;
136
+ new_v := (log_data#>>'{h,-1,v}')::int + 1;
139
137
 
140
- size := jsonb_array_length(NEW.log_data->'h');
138
+ size := jsonb_array_length(log_data->'h');
141
139
  version := logidze_version(new_v, changes, ts);
142
140
 
143
141
  IF (
144
142
  debounce_time IS NOT NULL AND
145
- (version->>'ts')::bigint - (NEW.log_data#>'{h,-1,ts}')::text::bigint <= debounce_time
143
+ (version->>'ts')::bigint - (log_data#>'{h,-1,ts}')::text::bigint <= debounce_time
146
144
  ) THEN
147
145
  -- merge new version with the previous one
148
- new_v := (NEW.log_data#>>'{h,-1,v}')::int;
149
- version := logidze_version(new_v, (NEW.log_data#>'{h,-1,c}')::jsonb || changes, ts);
146
+ new_v := (log_data#>>'{h,-1,v}')::int;
147
+ version := logidze_version(new_v, (log_data#>'{h,-1,c}')::jsonb || changes, ts);
150
148
  -- remove the previous version from log
151
- NEW.log_data := jsonb_set(
152
- NEW.log_data,
149
+ log_data := jsonb_set(
150
+ log_data,
153
151
  '{h}',
154
- (NEW.log_data->'h') - (size - 1)
152
+ (log_data->'h') - (size - 1)
155
153
  );
156
154
  END IF;
157
155
 
158
- NEW.log_data := jsonb_set(
159
- NEW.log_data,
156
+ log_data := jsonb_set(
157
+ log_data,
160
158
  ARRAY['h', size::text],
161
159
  version,
162
160
  true
163
161
  );
164
162
 
165
- NEW.log_data := jsonb_set(
166
- NEW.log_data,
163
+ log_data := jsonb_set(
164
+ log_data,
167
165
  '{v}',
168
166
  to_jsonb(new_v)
169
167
  );
170
168
 
171
169
  IF history_limit IS NOT NULL AND history_limit <= size THEN
172
- NEW.log_data := logidze_compact_history(NEW.log_data, size - history_limit + 1);
170
+ log_data := logidze_compact_history(log_data, size - history_limit + 1);
173
171
  END IF;
172
+
173
+ NEW.log_data := log_data;
174
174
  END IF;
175
175
 
176
- return NEW;
176
+ RETURN NEW; -- result
177
177
  EXCEPTION
178
178
  WHEN OTHERS THEN
179
179
  GET STACKED DIAGNOSTICS err_sqlstate = RETURNED_SQLSTATE,
@@ -0,0 +1,3 @@
1
+ CREATE OR REPLACE FUNCTION logidze_logger_after() RETURNS TRIGGER AS $body$
2
+ -- version: 4
3
+ <%= generate_logidze_logger_after %>
@@ -6,8 +6,6 @@ require "logidze/utils/function_definitions"
6
6
  require_relative "../inject_sql"
7
7
  require_relative "../fx_helper"
8
8
 
9
- using RubyNext
10
-
11
9
  module Logidze
12
10
  module Generators
13
11
  class InstallGenerator < ::Rails::Generators::Base # :nodoc:
@@ -19,7 +17,7 @@ module Logidze
19
17
  source_paths << File.expand_path("functions", __dir__)
20
18
 
21
19
  class_option :update, type: :boolean, optional: true,
22
- desc: "Define whether this is an update migration"
20
+ desc: "Define whether this is an update migration"
23
21
 
24
22
  def generate_migration
25
23
  migration_template = fx? ? "migration_fx.rb.erb" : "migration.rb.erb"
@@ -81,6 +79,17 @@ module Logidze
81
79
  def function_definitions
82
80
  @function_definitions ||= Logidze::Utils::FunctionDefinitions.from_fs
83
81
  end
82
+
83
+ # Generate `logidze_logger_after.sql` from the regular `logidze_logger.sql`
84
+ # by find-and-replacing a few lines
85
+ def generate_logidze_logger_after
86
+ source = File.read(File.join(__dir__, "functions", "logidze_logger.sql"))
87
+ source.sub!(/^CREATE OR REPLACE FUNCTION logidze_logger.*$/, "")
88
+ source.sub!(/^ -- version.*$/, "")
89
+ source.gsub!("RETURN NEW; -- pass", "RETURN NULL;")
90
+ source.gsub!("RETURN NEW; -- result", " EXECUTE format('UPDATE %I.%I SET \"log_data\" = $1 WHERE ctid = %L', TG_TABLE_SCHEMA, TG_TABLE_NAME, NEW.CTID) USING NEW.log_data;\n RETURN NULL;")
91
+ source
92
+ end
84
93
  end
85
94
 
86
95
  def self.next_migration_number(dir)
@@ -5,8 +5,6 @@ require "rails/generators/active_record/migration/migration_generator"
5
5
  require_relative "../inject_sql"
6
6
  require_relative "../fx_helper"
7
7
 
8
- using RubyNext
9
-
10
8
  module Logidze
11
9
  module Generators
12
10
  class ModelGenerator < ::ActiveRecord::Generators::Base # :nodoc:
@@ -19,13 +17,13 @@ module Logidze
19
17
  class_option :limit, type: :numeric, optional: true, desc: "Specify history size limit"
20
18
 
21
19
  class_option :debounce_time, type: :numeric, optional: true,
22
- desc: "Specify debounce time in millisecond"
20
+ desc: "Specify debounce time in millisecond"
23
21
 
24
22
  class_option :backfill, type: :boolean, optional: true,
25
- desc: "Add query to backfill existing records history"
23
+ desc: "Add query to backfill existing records history"
26
24
 
27
25
  class_option :only_trigger, type: :boolean, optional: true,
28
- desc: "Create trigger-only migration"
26
+ desc: "Create trigger-only migration"
29
27
 
30
28
  class_option :path, type: :string, optional: true, desc: "Specify path to the model file"
31
29
 
@@ -33,12 +31,14 @@ module Logidze
33
31
  class_option :only, type: :array, optional: true
34
32
 
35
33
  class_option :timestamp_column, type: :string, optional: true,
36
- desc: "Specify timestamp column"
34
+ desc: "Specify timestamp column"
37
35
 
38
36
  class_option :name, type: :string, optional: true, desc: "Migration name"
39
37
 
40
38
  class_option :update, type: :boolean, optional: true,
41
- desc: "Define whether this is an update migration"
39
+ desc: "Define whether this is an update migration"
40
+
41
+ class_option :after_trigger, type: :boolean, optional: true, desc: "Use after trigger"
42
42
 
43
43
  def generate_migration
44
44
  if options[:except] && options[:only]
@@ -51,7 +51,9 @@ module Logidze
51
51
  def generate_fx_trigger
52
52
  return unless fx?
53
53
 
54
- template "logidze.sql", "db/triggers/logidze_on_#{table_name}_v#{next_version.to_s.rjust(2, "0")}.sql"
54
+ template_name = after_trigger? ? "logidze_after.sql" : "logidze.sql"
55
+
56
+ template template_name, "db/triggers/logidze_on_#{table_name}_v#{next_version.to_s.rjust(2, "0")}.sql"
55
57
  end
56
58
 
57
59
  def inject_logidze_to_model
@@ -94,6 +96,10 @@ module Logidze
94
96
  options[:update]
95
97
  end
96
98
 
99
+ def after_trigger?
100
+ options[:after_trigger]
101
+ end
102
+
97
103
  def filtered_columns
98
104
  format_pgsql_array(options[:only] || options[:except])
99
105
  end
@@ -37,7 +37,7 @@ class <%= @migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::M
37
37
 
38
38
  <%- end -%>
39
39
  execute <<~SQL
40
- <%= inject_sql("logidze.sql", indent: 10) %>
40
+ <%= inject_sql(after_trigger? ? "logidze_after.sql" : "logidze.sql", indent: 10) %>
41
41
  SQL
42
42
  end
43
43
 
@@ -0,0 +1,6 @@
1
+ CREATE TRIGGER <%= %Q("logidze_on_#{full_table_name}") %>
2
+ AFTER UPDATE OR INSERT ON <%= %Q("#{full_table_name}") %> FOR EACH ROW
3
+ WHEN (coalesce(current_setting('logidze.disabled', true), '') <> 'on' AND pg_trigger_depth() < 1)
4
+ -- Parameters: history_size_limit (integer), timestamp_column (text), filtered_columns (text[]),
5
+ -- include_columns (boolean), debounce_time_ms (integer)
6
+ EXECUTE PROCEDURE logidze_logger_after(<%= logidze_logger_parameters %>);
@@ -5,11 +5,6 @@ module Logidze
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- if Rails::VERSION::MAJOR == 5
9
- require "logidze/ignore_log_data/cast_attribute_patch"
10
- include CastAttributePatch
11
- end
12
-
13
8
  scope :with_log_data, lambda {
14
9
  if ignored_columns == ["log_data"]
15
10
  select(arel_table[Arel.star])
data/lib/logidze/model.rb CHANGED
@@ -3,8 +3,6 @@
3
3
  require "active_support"
4
4
 
5
5
  module Logidze
6
- using RubyNext
7
-
8
6
  # Extends model with methods to browse history
9
7
  module Model
10
8
  require "logidze/history/type"
@@ -96,6 +94,20 @@ module Logidze
96
94
 
97
95
  build_dup(log_entry, time)
98
96
  end
97
+
98
+ def logidze_versions(reverse: false, include_self: false)
99
+ versions_meta = log_data.versions.dup
100
+
101
+ if reverse
102
+ versions_meta.reverse!
103
+ versions_meta.shift unless include_self
104
+ else
105
+ versions_meta.pop unless include_self
106
+ end
107
+
108
+ Enumerator.new { |yielder| versions_meta.each { yielder << at(version: _1.version) } }
109
+ end
110
+
99
111
  # rubocop: enable Metrics/MethodLength
100
112
 
101
113
  # Revert record to the version at specified time (without saving to DB)
@@ -116,6 +128,7 @@ module Logidze
116
128
 
117
129
  # Return a dirty copy of specified version of record
118
130
  def at_version(version)
131
+ return nil unless log_data
119
132
  return self if log_data.version == version
120
133
 
121
134
  log_entry = log_data.find_by_version(version)
@@ -217,7 +230,7 @@ module Logidze
217
230
 
218
231
  # Loads log_data field from the database, stores to the attributes hash and returns it
219
232
  def reload_log_data
220
- self.log_data = self.class.where(self.class.primary_key => id).pluck("#{self.class.table_name}.log_data".to_sym).first
233
+ self.log_data = self.class.where(self.class.primary_key => id).pluck(:"#{self.class.table_name}.log_data").first
221
234
  end
222
235
 
223
236
  # Nullify log_data column for a single record
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./function_definitions"
4
- require_relative "./pending_migration_error"
3
+ require_relative "function_definitions"
4
+ require_relative "pending_migration_error"
5
5
 
6
6
  module Logidze
7
7
  module Utils
@@ -31,10 +31,10 @@ module Logidze
31
31
  def notify_or_raise!
32
32
  case Logidze.on_pending_upgrade
33
33
  when :warn
34
- warn "\n**************************************************\n"\
35
- "⛔️ WARNING: Logidze needs an upgrade and might not work correctly.\n"\
36
- "Please, make sure to run `bundle exec rails generate logidze:install --update` "\
37
- "and apply generated migration."\
34
+ warn "\n**************************************************\n" \
35
+ "⛔️ WARNING: Logidze needs an upgrade and might not work correctly.\n" \
36
+ "Please, make sure to run `bundle exec rails generate logidze:install --update` " \
37
+ "and apply generated migration." \
38
38
  "\n**************************************************\n\n"
39
39
  when :raise
40
40
  raise Logidze::Utils::PendingMigrationError, "Logidze needs upgrade. Run `bundle exec rails generate logidze:install --update` and apply generated migration."
@@ -5,19 +5,17 @@ require "rails/generators"
5
5
  module Logidze
6
6
  module Utils
7
7
  class PendingMigrationError < StandardError
8
- if Rails::VERSION::MAJOR >= 6
9
- require "active_record"
10
- require "active_support/actionable_error"
11
- include ActiveSupport::ActionableError
8
+ require "active_record"
9
+ require "active_support/actionable_error"
10
+ include ActiveSupport::ActionableError
12
11
 
13
- action "Upgrade Logidze" do
14
- Rails::Generators.invoke("logidze:install", ["--update"])
15
- ActiveRecord::Tasks::DatabaseTasks.migrate
16
- if ActiveRecord::Base.dump_schema_after_migration
17
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(
18
- ActiveRecord::Base.connection_db_config
19
- )
20
- end
12
+ action "Upgrade Logidze" do
13
+ Rails::Generators.invoke("logidze:install", ["--update"])
14
+ ActiveRecord::Tasks::DatabaseTasks.migrate
15
+ if ActiveRecord::Base.dump_schema_after_migration
16
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(
17
+ ActiveRecord::Base.connection_db_config
18
+ )
21
19
  end
22
20
  end
23
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Logidze
4
- VERSION = "1.2.3"
4
+ VERSION = "1.3.0"
5
5
  end
data/lib/logidze.rb CHANGED
@@ -5,7 +5,6 @@ require "logidze/version"
5
5
  # Logidze provides tools for adding in-table JSON-based audit to DB tables
6
6
  # and ActiveRecord extensions to work with changes history.
7
7
  module Logidze
8
- require "ruby-next"
9
8
  require "logidze/history"
10
9
  require "logidze/model"
11
10
  require "logidze/versioned_association"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logidze
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-04 00:00:00.000000000 Z
11
+ date: 2024-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -16,42 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: '6.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5.0'
26
+ version: '6.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '5.0'
33
+ version: '6.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '5.0'
41
- - !ruby/object:Gem::Dependency
42
- name: ruby-next-core
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.9'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.9'
40
+ version: '6.0'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: ammeter
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +86,14 @@ dependencies:
100
86
  requirements:
101
87
  - - ">="
102
88
  - !ruby/object:Gem::Version
103
- version: '0.18'
89
+ version: '1.0'
104
90
  type: :development
105
91
  prerelease: false
106
92
  version_requirements: !ruby/object:Gem::Requirement
107
93
  requirements:
108
94
  - - ">="
109
95
  - !ruby/object:Gem::Version
110
- version: '0.18'
96
+ version: '1.0'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: rake
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +114,14 @@ dependencies:
128
114
  requirements:
129
115
  - - ">="
130
116
  - !ruby/object:Gem::Version
131
- version: '3.4'
117
+ version: '4.0'
132
118
  type: :development
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
121
  requirements:
136
122
  - - ">="
137
123
  - !ruby/object:Gem::Version
138
- version: '3.4'
124
+ version: '4.0'
139
125
  - !ruby/object:Gem::Dependency
140
126
  name: timecop
141
127
  requirement: !ruby/object:Gem::Requirement
@@ -167,6 +153,7 @@ files:
167
153
  - lib/generators/logidze/install/functions/logidze_compact_history.sql
168
154
  - lib/generators/logidze/install/functions/logidze_filter_keys.sql
169
155
  - lib/generators/logidze/install/functions/logidze_logger.sql
156
+ - lib/generators/logidze/install/functions/logidze_logger_after.sql
170
157
  - lib/generators/logidze/install/functions/logidze_snapshot.sql
171
158
  - lib/generators/logidze/install/functions/logidze_version.sql
172
159
  - lib/generators/logidze/install/install_generator.rb
@@ -177,6 +164,7 @@ files:
177
164
  - lib/generators/logidze/model/model_generator.rb
178
165
  - lib/generators/logidze/model/templates/migration.rb.erb
179
166
  - lib/generators/logidze/model/triggers/logidze.sql
167
+ - lib/generators/logidze/model/triggers/logidze_after.sql
180
168
  - lib/logidze.rb
181
169
  - lib/logidze/engine.rb
182
170
  - lib/logidze/has_logidze.rb
@@ -184,7 +172,6 @@ files:
184
172
  - lib/logidze/history/type.rb
185
173
  - lib/logidze/history/version.rb
186
174
  - lib/logidze/ignore_log_data.rb
187
- - lib/logidze/ignore_log_data/cast_attribute_patch.rb
188
175
  - lib/logidze/meta.rb
189
176
  - lib/logidze/model.rb
190
177
  - lib/logidze/utils/check_pending.rb
@@ -209,14 +196,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
209
196
  requirements:
210
197
  - - ">="
211
198
  - !ruby/object:Gem::Version
212
- version: 2.5.0
199
+ version: 2.7.0
213
200
  required_rubygems_version: !ruby/object:Gem::Requirement
214
201
  requirements:
215
202
  - - ">="
216
203
  - !ruby/object:Gem::Version
217
204
  version: '0'
218
205
  requirements: []
219
- rubygems_version: 3.3.11
206
+ rubygems_version: 3.4.20
220
207
  signing_key:
221
208
  specification_version: 4
222
209
  summary: PostgreSQL JSONB-based model changes tracking
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Logidze
4
- module IgnoreLogData
5
- # Fixes unexpected behavior (see more https://github.com/rails/rails/pull/34528):
6
- # instead of using a type passed to `attribute` call, ignored column uses
7
- # a type coming from the DB (in this case `.log_data` would return a plain hash
8
- # instead of `Logidze::History`)
9
- module CastAttributePatch
10
- def log_data
11
- return attributes["log_data"] if attributes["log_data"].is_a?(Logidze::History)
12
-
13
- self.log_data = Logidze::History::Type.new.cast_value(super)
14
- end
15
- end
16
- end
17
- end