logidze 1.0.0.rc1 → 1.2.1
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/CHANGELOG.md +38 -1
- data/README.md +69 -18
- data/lib/generators/logidze/install/functions/logidze_capture_exception.sql +23 -0
- data/lib/generators/logidze/install/functions/logidze_compact_history.sql +1 -1
- data/lib/generators/logidze/install/functions/logidze_filter_keys.sql +1 -1
- data/lib/generators/logidze/install/functions/logidze_logger.sql +69 -16
- data/lib/generators/logidze/install/functions/logidze_snapshot.sql +10 -1
- data/lib/generators/logidze/install/functions/logidze_version.sql +2 -1
- data/lib/generators/logidze/install/install_generator.rb +2 -17
- data/lib/generators/logidze/install/templates/hstore.rb.erb +1 -1
- data/lib/generators/logidze/install/templates/migration.rb.erb +1 -1
- data/lib/generators/logidze/install/templates/migration_fx.rb.erb +1 -1
- data/lib/generators/logidze/model/model_generator.rb +8 -3
- data/lib/generators/logidze/model/templates/migration.rb.erb +14 -6
- data/lib/generators/logidze/model/triggers/logidze.sql +2 -2
- data/lib/logidze/engine.rb +9 -0
- data/lib/logidze/history.rb +1 -1
- data/lib/logidze/model.rb +4 -10
- data/lib/logidze/utils/check_pending.rb +57 -0
- data/lib/logidze/utils/function_definitions.rb +49 -0
- data/lib/logidze/utils/pending_migration_error.rb +25 -0
- data/lib/logidze/version.rb +1 -1
- data/lib/logidze.rb +11 -1
- metadata +27 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be9e11a375ab711ba02349e3cd14fbd4503af6572d969ced6db24bd36407bf05
|
|
4
|
+
data.tar.gz: '03885f890051fc938cba4089798bcc8b1b753a5ae941c5d93907536e1685ff94'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 24bc6a181263eaeb98762e8c183ba74b717a3195d2809460ceeddfbeefdc63c4b72e3c5da2b8426bba2722c765a41c27bf3ff2d3e265b5760a561795e205ee5a
|
|
7
|
+
data.tar.gz: 96f0e22ccad449d642320a9bf105e05ed15623ecaa1a52e453bfda356df2dbf9cb13eda235c6e288e1cf62d0484234f92104673c7ef15c9fbfe135d8bb757b16
|
data/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
## master (unreleased)
|
|
4
4
|
|
|
5
|
-
## 1.
|
|
5
|
+
## 1.2.1 (2022-01-13)
|
|
6
|
+
|
|
7
|
+
- [Fixes [#207](https://github.com/palkan/logidze/issues/207)] Add support for the use of `table_name_prefix` or `table_name_suffix`. ([@cavi21][])
|
|
8
|
+
|
|
9
|
+
- [Fixes [#205](https://github.com/palkan/logidze/issues/205)] Allow `rails destroy logidze:model SomeModel` to delete the migration file. ([@danielmklein][])
|
|
10
|
+
|
|
11
|
+
## 1.2.0 (2021-06-11)
|
|
12
|
+
|
|
13
|
+
- Add user-defined exception handling ([@skryukov][])
|
|
14
|
+
|
|
15
|
+
By default, Logidze raises an exception which causes the entire transaction to fail.
|
|
16
|
+
To change this behavior, it's now possible to override `logidze_capture_exception(error_data jsonb)` function.
|
|
17
|
+
|
|
18
|
+
- [Fixes [#69](https://github.com/palkan/logidze/issues/69)] Fallback on NUMERIC_VALUE_OUT_OF_RANGE exception ([@skryukov][])
|
|
19
|
+
|
|
20
|
+
- [Fixes [#192](https://github.com/palkan/logidze/issues/192)] Skip `log_data` column during `apply_column_diff` ([@skryukov][])
|
|
21
|
+
|
|
22
|
+
## 1.1.0 (2021-03-31)
|
|
23
|
+
|
|
24
|
+
- Add pending upgrade checks [Experimental]. ([@skryukov][])
|
|
25
|
+
|
|
26
|
+
Now Logidze can check for a pending upgrade. Use `Logidze.pending_upgrade = :warn` to be notified by warning, or `Logidze.pending_upgrade = :error` if you want Logidze to raise an error.
|
|
27
|
+
|
|
28
|
+
- [Fixes [#171](https://github.com/palkan/logidze/issues/171)] Stringify jsonb column values within snapshots. ([@skryukov][])
|
|
29
|
+
|
|
30
|
+
- [Fixes [#175](https://github.com/palkan/logidze/issues/175)] Set dynamic ActiveRecord version for migrations. ([@skryukov][])
|
|
31
|
+
|
|
32
|
+
- [Fixes [#184](https://github.com/palkan/logidze/issues/184)] Remove Rails meta-gem dependency ([@bf4][])
|
|
33
|
+
|
|
34
|
+
## 1.0.0 (2020-11-09)
|
|
35
|
+
|
|
36
|
+
- Add `--name` option to model generator to specify the migration name. ([@palkan][])
|
|
37
|
+
|
|
38
|
+
When you update Logidze installation for a model multiple times, you might hit the `DuplicateMigrationNameError` (see [#167](https://github.com/palkan/logidze/issues/167)).
|
|
6
39
|
|
|
7
40
|
- Add `.with_full_snapshot` to add full snapshots to the log instead of diffs. ([@palkan][])
|
|
8
41
|
|
|
@@ -330,3 +363,7 @@ This is a quick fix for a more general problem (see [#59](https://github.com/pal
|
|
|
330
363
|
[@zocoi]: https://github.com/zocoi
|
|
331
364
|
[@duderman]: https://github.com/duderman
|
|
332
365
|
[@oleg-kiviljov]: https://github.com/oleg-kiviljov
|
|
366
|
+
[@skryukov]: https://github.com/skryukov
|
|
367
|
+
[@bf4]: https://github.com/bf4
|
|
368
|
+
[@cavi21]: https://github.com/cavi21
|
|
369
|
+
[@danielmklein]: https://github.com/danielmklein
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[](http://cultofmartians.com)
|
|
2
2
|
[](https://rubygems.org/gems/logidze)
|
|
3
|
-

|
|
3
|
+
[](https://github.com/palkan/logidze/actions)
|
|
4
4
|
[](https://www.codetriage.com/palkan/logidze)
|
|
5
5
|
|
|
6
6
|
# Logidze
|
|
@@ -10,8 +10,6 @@ Logidze provides tools for logging DB records changes when using PostgreSQL (>=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.
|
|
12
12
|
|
|
13
|
-
**❗️ IMPORTANT:** This page contains documentation for the upcoming v1.0. For the latest release documentation see the [0-stable branch](https://github.com/palkan/logidze/tree/0-stable). If you're just starting with Logidze, we recommend using the latest release candidate (`1.0.0.rc1`).
|
|
14
|
-
|
|
15
13
|
🤔 [How is Logidze pronounced?](https://github.com/palkan/logidze/issues/73)
|
|
16
14
|
|
|
17
15
|
Other requirements:
|
|
@@ -24,18 +22,19 @@ Other requirements:
|
|
|
24
22
|
|
|
25
23
|
## Links
|
|
26
24
|
|
|
25
|
+
- [Logidze 1.0: Active Record, Postgres, Rails, and time travel](https://evilmartians.com/chronicles/logidze-1-0-active-record-postgresql-rails-and-time-travel?utm_source=logidze)
|
|
27
26
|
- [Logidze: for all those tired of versioning data](https://evilmartians.com/chronicles/introducing-logidze?utm_source=logidze)
|
|
28
27
|
|
|
29
28
|
## Table of contents
|
|
30
29
|
|
|
31
|
-
- [Main concepts](#main-concepts)
|
|
32
30
|
- [Installation & Configuration](#installation)
|
|
33
31
|
- [Using with schema.rb](#using-with-schemarb)
|
|
34
|
-
- [
|
|
32
|
+
- [Configuring models](#configuring-models)
|
|
35
33
|
- [Backfill data](#backfill-data)
|
|
36
|
-
- [Log size
|
|
34
|
+
- [Log size limits](#log-size-limits)
|
|
37
35
|
- [Tracking only selected columns](#tracking-only-selected-columns)
|
|
38
36
|
- [Logs timestamps](#logs-timestamps)
|
|
37
|
+
- [Undoing a Generated Invocation](#undoing-a-generated-invocation)
|
|
39
38
|
- [Usage](#usage)
|
|
40
39
|
- [Basic API](#basic-api)
|
|
41
40
|
- [Track meta information](#track-meta-information)
|
|
@@ -46,6 +45,7 @@ Other requirements:
|
|
|
46
45
|
- [Associations versioning](#associations-versioning)
|
|
47
46
|
- [Dealing with large logs](#dealing-with-large-logs)
|
|
48
47
|
- [Handling records deletion](#handling-records-deletion)
|
|
48
|
+
- [Handling PG exceptions](#handling-pg-exceptions)
|
|
49
49
|
- [Upgrading](#upgrading)
|
|
50
50
|
- [Log format](#log-format)
|
|
51
51
|
- [Troubleshooting 🚨](#troubleshooting)
|
|
@@ -56,7 +56,7 @@ Other requirements:
|
|
|
56
56
|
Add Logidze to your application's Gemfile:
|
|
57
57
|
|
|
58
58
|
```ruby
|
|
59
|
-
gem "logidze", "1.
|
|
59
|
+
gem "logidze", "~> 1.1"
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
Install required DB extensions and create trigger function:
|
|
@@ -135,8 +135,8 @@ Model.create_logidze_snapshot
|
|
|
135
135
|
Model.create_logidze_snapshot(timestamp: :created_at)
|
|
136
136
|
|
|
137
137
|
# filter columns
|
|
138
|
-
Model.create_logidze_snapshot(only: %
|
|
139
|
-
Model.create_logidze_snapshot(except: %
|
|
138
|
+
Model.create_logidze_snapshot(only: %w[name])
|
|
139
|
+
Model.create_logidze_snapshot(except: %w[password])
|
|
140
140
|
|
|
141
141
|
# or call a similar method (but with !) on a record
|
|
142
142
|
|
|
@@ -179,6 +179,16 @@ bundle exec rails generate logidze:model Post --timestamp_column time
|
|
|
179
179
|
bundle exec rails generate logidze:model Post --timestamp_column nil # "null" and "false" will also work
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
+
### Undoing a Generated Invocation
|
|
183
|
+
|
|
184
|
+
If you would like to re-do your `rails generate` anew, as with other generators you can use `rails destroy` to revert it, which will delete the migration file and undo the injection of `has_logidze` into the model file:
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
bundle exec rails destroy logidze:model Post
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**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
|
+
|
|
182
192
|
## Usage
|
|
183
193
|
|
|
184
194
|
### Basic API
|
|
@@ -275,11 +285,13 @@ Logidze.append_on_undo = true
|
|
|
275
285
|
You can store any meta information you want inside your version (it could be IP address, user agent, etc.). To add it you should wrap your code with a block:
|
|
276
286
|
|
|
277
287
|
```ruby
|
|
278
|
-
Logidze.with_meta(ip: request.ip) do
|
|
288
|
+
Logidze.with_meta({ip: request.ip}) do
|
|
279
289
|
post.save!
|
|
280
290
|
end
|
|
281
291
|
```
|
|
282
292
|
|
|
293
|
+
**NOTE:** You should pass metadata as a Hash; passing keyword arguments doesn't work in Ruby 3.0+.
|
|
294
|
+
|
|
283
295
|
Meta expects a hash to be passed so you won't need to encode and decode JSON manually.
|
|
284
296
|
|
|
285
297
|
By default `.with_meta` wraps the block into a DB transaction. That could lead to an unexpected behavior, especially, when using `.with_meta` within an around_action. To avoid wrapping the block into a DB transaction use `transactional: false` option.
|
|
@@ -436,12 +448,21 @@ If you want to keep changes history after records deletion as well, consider usi
|
|
|
436
448
|
|
|
437
449
|
See also the discussion: [#61](https://github.com/palkan/logidze/issues/61).
|
|
438
450
|
|
|
451
|
+
## Handling PG exceptions
|
|
452
|
+
|
|
453
|
+
By default, Logidze raises an exception which causes the entire transaction to fail.
|
|
454
|
+
To change this behavior, it's now possible to override `logidze_capture_exception(error_data jsonb)` function.
|
|
455
|
+
|
|
456
|
+
For example, you may want to raise a warning instead of an exception and complete the transaction without updating log_data.
|
|
457
|
+
|
|
458
|
+
Related issues: [#193](https://github.com/palkan/logidze/issues/193)
|
|
459
|
+
|
|
439
460
|
## Upgrading
|
|
440
461
|
|
|
441
462
|
We try to make an upgrade process as simple as possible. For now, the only required action is to create and run a migration:
|
|
442
463
|
|
|
443
464
|
```sh
|
|
444
|
-
rails generate logidze:install --update
|
|
465
|
+
bundle exec rails generate logidze:install --update
|
|
445
466
|
```
|
|
446
467
|
|
|
447
468
|
This updates core `logdize_logger` DB function. No need to update tables or triggers.
|
|
@@ -451,23 +472,37 @@ This updates core `logdize_logger` DB function. No need to update tables or trig
|
|
|
451
472
|
If you want to update Logidze settings for the model, run migration with `--update` flag:
|
|
452
473
|
|
|
453
474
|
```sh
|
|
454
|
-
rails generate logidze:model Post --update --only=title,body,rating
|
|
475
|
+
bundle exec rails generate logidze:model Post --update --only=title,body,rating
|
|
455
476
|
```
|
|
456
477
|
|
|
478
|
+
You can also use the `--name` option to specify the migration name to avoid duplicate migration names:
|
|
479
|
+
|
|
480
|
+
```sh
|
|
481
|
+
$ bundle exec rails generate logidze:model Post --update --only=title,body,rating --name add_only_filter_to_posts_log_data
|
|
482
|
+
|
|
483
|
+
create db/migrate/20202309142344_add_only_filter_to_posts_log_data.rb
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Pending upgrade check [Experimental]
|
|
487
|
+
|
|
488
|
+
Logidze can check for a pending upgrade. Use `Logidze.on_pending_upgrade = :warn` to be notified by warning, or `Logidze.on_pending_upgrade = :error` if you want Logidze to raise an error.
|
|
489
|
+
|
|
457
490
|
### Upgrading from 0.x to 1.0 (edge)
|
|
458
491
|
|
|
459
492
|
#### Schema and migrations
|
|
460
493
|
|
|
461
|
-
Most SQL
|
|
494
|
+
Most SQL function definitions have changed without backward compatibility.
|
|
462
495
|
Perform the following steps to upgrade:
|
|
463
496
|
|
|
464
|
-
1. Re-install Logidze: `rails generate logidze:install --update`.
|
|
497
|
+
1. Re-install Logidze: `bundle exec rails generate logidze:install --update`.
|
|
498
|
+
|
|
499
|
+
1. Re-install Logidze triggers **for all models**: `bundle exec rails generate logidze:model <model> --update`.
|
|
465
500
|
|
|
466
|
-
|
|
501
|
+
**NOTE:** If you had previously specified whitelist/blacklist attributes, you will need to include the `--only`/`--except` [option](#tracking-only-selected-columns) as appropriate. You can easily copy these column lists from the previous logidze migration for the model.
|
|
467
502
|
|
|
468
503
|
1. Remove the `include Logidze::Migration` line from the old migration files (if any)—this module has been removed.
|
|
469
504
|
|
|
470
|
-
Rewrite
|
|
505
|
+
Rewrite legacy logidze migrations to not use the `#current_setting(name)` and `#current_setting_missing_supported?` methods, or copy them from the latest [0.x release](https://github.com/palkan/logidze/blob/0-stable/lib/logidze/migration.rb).
|
|
471
506
|
|
|
472
507
|
#### API changes
|
|
473
508
|
|
|
@@ -532,11 +567,27 @@ First, when restoring data dumps you should consider using `--disable-triggers`
|
|
|
532
567
|
|
|
533
568
|
When restoring data dumps for a particular PostgreSQL schema (e.g., when using Apartment), you may encounter the issue with non-existent Logidze functions. That happens because `pg_dump` adds `SELECT pg_catalog.set_config('search_path', '', false);`, and, thus, breaks our existing triggers/functions, because they live either in "public" or in a tenant's namespace (see [this thread](https://postgrespro.com/list/thread-id/2448092)).
|
|
534
569
|
|
|
570
|
+
### `PG::NumericValueOutOfRange: ERROR: value overflows numeric format`
|
|
571
|
+
|
|
572
|
+
Due to the usage of `hstore_to_jsonb_loose` under the hood, there could be a situation when you have a string representing a number in the scientific notation (e.g., "557236406134e62000323100"). Postgres would try to convert it to a number (a pretty big one, for sure) and fail with the exception.
|
|
573
|
+
|
|
574
|
+
Related issues: [#69](https://github.com/palkan/logidze/issues/69).
|
|
575
|
+
|
|
535
576
|
## Development
|
|
536
577
|
|
|
537
|
-
|
|
578
|
+
This project requires a PostgreSQL instance running with the following setup:
|
|
579
|
+
|
|
580
|
+
```sh
|
|
581
|
+
# For testing
|
|
582
|
+
createdb -h postgres -U postgres logidze_test
|
|
583
|
+
|
|
584
|
+
# For benchmarks
|
|
585
|
+
createdb -h postgres -U postgres logidze_bench
|
|
586
|
+
createdb -h postgres -U postgres logidze_perf_bench
|
|
587
|
+
psql -d logidze_bench -c 'CREATE EXTENSION IF NOT EXISTS hstore;'
|
|
588
|
+
```
|
|
538
589
|
|
|
539
|
-
|
|
590
|
+
This project is compatible with [Reusable Docker environment](https://evilmartians.com/chronicles/reusable-development-containers-with-docker-compose-and-dip) setup.
|
|
540
591
|
|
|
541
592
|
## Contributing
|
|
542
593
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
CREATE OR REPLACE FUNCTION logidze_capture_exception(error_data jsonb) RETURNS boolean AS $body$
|
|
2
|
+
-- version: 1
|
|
3
|
+
BEGIN
|
|
4
|
+
-- Feel free to change this function to change Logidze behavior on exception.
|
|
5
|
+
--
|
|
6
|
+
-- Return `false` to raise exception or `true` to commit record changes.
|
|
7
|
+
--
|
|
8
|
+
-- `error_data` contains:
|
|
9
|
+
-- - returned_sqlstate
|
|
10
|
+
-- - message_text
|
|
11
|
+
-- - pg_exception_detail
|
|
12
|
+
-- - pg_exception_hint
|
|
13
|
+
-- - pg_exception_context
|
|
14
|
+
-- - schema_name
|
|
15
|
+
-- - table_name
|
|
16
|
+
-- Learn more about available keys:
|
|
17
|
+
-- https://www.postgresql.org/docs/9.6/plpgsql-control-structures.html#PLPGSQL-EXCEPTION-DIAGNOSTICS-VALUES
|
|
18
|
+
--
|
|
19
|
+
|
|
20
|
+
return false;
|
|
21
|
+
END;
|
|
22
|
+
$body$
|
|
23
|
+
LANGUAGE plpgsql;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
-- version: 1
|
|
2
1
|
CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
|
|
2
|
+
-- version: 2
|
|
3
3
|
DECLARE
|
|
4
4
|
changes jsonb;
|
|
5
5
|
version jsonb;
|
|
@@ -9,26 +9,32 @@ CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
|
|
|
9
9
|
history_limit integer;
|
|
10
10
|
debounce_time integer;
|
|
11
11
|
current_version integer;
|
|
12
|
-
|
|
12
|
+
k text;
|
|
13
13
|
iterator integer;
|
|
14
14
|
item record;
|
|
15
15
|
columns text[];
|
|
16
16
|
include_columns boolean;
|
|
17
17
|
ts timestamp with time zone;
|
|
18
18
|
ts_column text;
|
|
19
|
+
err_sqlstate text;
|
|
20
|
+
err_message text;
|
|
21
|
+
err_detail text;
|
|
22
|
+
err_hint text;
|
|
23
|
+
err_context text;
|
|
24
|
+
err_table_name text;
|
|
25
|
+
err_schema_name text;
|
|
26
|
+
err_jsonb jsonb;
|
|
27
|
+
err_captured boolean;
|
|
19
28
|
BEGIN
|
|
20
29
|
ts_column := NULLIF(TG_ARGV[1], 'null');
|
|
21
30
|
columns := NULLIF(TG_ARGV[2], 'null');
|
|
22
31
|
include_columns := NULLIF(TG_ARGV[3], 'null');
|
|
23
32
|
|
|
24
33
|
IF TG_OP = 'INSERT' THEN
|
|
25
|
-
-- always exclude log_data column
|
|
26
|
-
changes := to_jsonb(NEW.*) - 'log_data';
|
|
27
|
-
|
|
28
34
|
IF columns IS NOT NULL THEN
|
|
29
|
-
snapshot = logidze_snapshot(
|
|
35
|
+
snapshot = logidze_snapshot(to_jsonb(NEW.*), ts_column, columns, include_columns);
|
|
30
36
|
ELSE
|
|
31
|
-
snapshot = logidze_snapshot(
|
|
37
|
+
snapshot = logidze_snapshot(to_jsonb(NEW.*), ts_column);
|
|
32
38
|
END IF;
|
|
33
39
|
|
|
34
40
|
IF snapshot#>>'{h, -1, c}' != '{}' THEN
|
|
@@ -38,13 +44,10 @@ CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
|
|
|
38
44
|
ELSIF TG_OP = 'UPDATE' THEN
|
|
39
45
|
|
|
40
46
|
IF OLD.log_data is NULL OR OLD.log_data = '{}'::jsonb THEN
|
|
41
|
-
-- always exclude log_data column
|
|
42
|
-
changes := to_jsonb(NEW.*) - 'log_data';
|
|
43
|
-
|
|
44
47
|
IF columns IS NOT NULL THEN
|
|
45
|
-
snapshot = logidze_snapshot(
|
|
48
|
+
snapshot = logidze_snapshot(to_jsonb(NEW.*), ts_column, columns, include_columns);
|
|
46
49
|
ELSE
|
|
47
|
-
snapshot = logidze_snapshot(
|
|
50
|
+
snapshot = logidze_snapshot(to_jsonb(NEW.*), ts_column);
|
|
48
51
|
END IF;
|
|
49
52
|
|
|
50
53
|
IF snapshot#>>'{h, -1, c}' != '{}' THEN
|
|
@@ -89,11 +92,37 @@ CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
|
|
|
89
92
|
changes := '{}';
|
|
90
93
|
|
|
91
94
|
IF (coalesce(current_setting('logidze.full_snapshot', true), '') = 'on') THEN
|
|
92
|
-
|
|
95
|
+
BEGIN
|
|
96
|
+
changes = hstore_to_jsonb_loose(hstore(NEW.*));
|
|
97
|
+
EXCEPTION
|
|
98
|
+
WHEN NUMERIC_VALUE_OUT_OF_RANGE THEN
|
|
99
|
+
changes = row_to_json(NEW.*)::jsonb;
|
|
100
|
+
FOR k IN (SELECT key FROM jsonb_each(changes))
|
|
101
|
+
LOOP
|
|
102
|
+
IF jsonb_typeof(changes->k) = 'object' THEN
|
|
103
|
+
changes = jsonb_set(changes, ARRAY[k], to_jsonb(changes->>k));
|
|
104
|
+
END IF;
|
|
105
|
+
END LOOP;
|
|
106
|
+
END;
|
|
93
107
|
ELSE
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
108
|
+
BEGIN
|
|
109
|
+
changes = hstore_to_jsonb_loose(
|
|
110
|
+
hstore(NEW.*) - hstore(OLD.*)
|
|
111
|
+
);
|
|
112
|
+
EXCEPTION
|
|
113
|
+
WHEN NUMERIC_VALUE_OUT_OF_RANGE THEN
|
|
114
|
+
changes = (SELECT
|
|
115
|
+
COALESCE(json_object_agg(key, value), '{}')::jsonb
|
|
116
|
+
FROM
|
|
117
|
+
jsonb_each(row_to_json(NEW.*)::jsonb)
|
|
118
|
+
WHERE NOT jsonb_build_object(key, value) <@ row_to_json(OLD.*)::jsonb);
|
|
119
|
+
FOR k IN (SELECT key FROM jsonb_each(changes))
|
|
120
|
+
LOOP
|
|
121
|
+
IF jsonb_typeof(changes->k) = 'object' THEN
|
|
122
|
+
changes = jsonb_set(changes, ARRAY[k], to_jsonb(changes->>k));
|
|
123
|
+
END IF;
|
|
124
|
+
END LOOP;
|
|
125
|
+
END;
|
|
97
126
|
END IF;
|
|
98
127
|
|
|
99
128
|
changes = changes - 'log_data';
|
|
@@ -145,6 +174,30 @@ CREATE OR REPLACE FUNCTION logidze_logger() RETURNS TRIGGER AS $body$
|
|
|
145
174
|
END IF;
|
|
146
175
|
|
|
147
176
|
return NEW;
|
|
177
|
+
EXCEPTION
|
|
178
|
+
WHEN OTHERS THEN
|
|
179
|
+
GET STACKED DIAGNOSTICS err_sqlstate = RETURNED_SQLSTATE,
|
|
180
|
+
err_message = MESSAGE_TEXT,
|
|
181
|
+
err_detail = PG_EXCEPTION_DETAIL,
|
|
182
|
+
err_hint = PG_EXCEPTION_HINT,
|
|
183
|
+
err_context = PG_EXCEPTION_CONTEXT,
|
|
184
|
+
err_schema_name = SCHEMA_NAME,
|
|
185
|
+
err_table_name = TABLE_NAME;
|
|
186
|
+
err_jsonb := jsonb_build_object(
|
|
187
|
+
'returned_sqlstate', err_sqlstate,
|
|
188
|
+
'message_text', err_message,
|
|
189
|
+
'pg_exception_detail', err_detail,
|
|
190
|
+
'pg_exception_hint', err_hint,
|
|
191
|
+
'pg_exception_context', err_context,
|
|
192
|
+
'schema_name', err_schema_name,
|
|
193
|
+
'table_name', err_table_name
|
|
194
|
+
);
|
|
195
|
+
err_captured = logidze_capture_exception(err_jsonb);
|
|
196
|
+
IF err_captured THEN
|
|
197
|
+
return NEW;
|
|
198
|
+
ELSE
|
|
199
|
+
RAISE;
|
|
200
|
+
END IF;
|
|
148
201
|
END;
|
|
149
202
|
$body$
|
|
150
203
|
LANGUAGE plpgsql;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
-- version: 1
|
|
2
1
|
CREATE OR REPLACE FUNCTION logidze_snapshot(item jsonb, ts_column text DEFAULT NULL, columns text[] DEFAULT NULL, include_columns boolean DEFAULT false) RETURNS jsonb AS $body$
|
|
2
|
+
-- version: 3
|
|
3
3
|
DECLARE
|
|
4
4
|
ts timestamp with time zone;
|
|
5
|
+
k text;
|
|
5
6
|
BEGIN
|
|
7
|
+
item = item - 'log_data';
|
|
6
8
|
IF ts_column IS NULL THEN
|
|
7
9
|
ts := statement_timestamp();
|
|
8
10
|
ELSE
|
|
@@ -13,6 +15,13 @@ CREATE OR REPLACE FUNCTION logidze_snapshot(item jsonb, ts_column text DEFAULT N
|
|
|
13
15
|
item := logidze_filter_keys(item, columns, include_columns);
|
|
14
16
|
END IF;
|
|
15
17
|
|
|
18
|
+
FOR k IN (SELECT key FROM jsonb_each(item))
|
|
19
|
+
LOOP
|
|
20
|
+
IF jsonb_typeof(item->k) = 'object' THEN
|
|
21
|
+
item := jsonb_set(item, ARRAY[k], to_jsonb(item->>k));
|
|
22
|
+
END IF;
|
|
23
|
+
END LOOP;
|
|
24
|
+
|
|
16
25
|
return json_build_object(
|
|
17
26
|
'v', 1,
|
|
18
27
|
'h', jsonb_build_array(
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
-- version: 1
|
|
2
1
|
CREATE OR REPLACE FUNCTION logidze_version(v bigint, data jsonb, ts timestamp with time zone) RETURNS jsonb AS $body$
|
|
2
|
+
-- version: 2
|
|
3
3
|
DECLARE
|
|
4
4
|
buf jsonb;
|
|
5
5
|
BEGIN
|
|
6
|
+
data = data - 'log_data';
|
|
6
7
|
buf := jsonb_build_object(
|
|
7
8
|
'ts',
|
|
8
9
|
(extract(epoch from ts) * 1000)::bigint,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "rails/generators"
|
|
4
4
|
require "rails/generators/active_record"
|
|
5
|
+
require "logidze/utils/function_definitions"
|
|
5
6
|
require_relative "../inject_sql"
|
|
6
7
|
require_relative "../fx_helper"
|
|
7
8
|
|
|
@@ -14,8 +15,6 @@ module Logidze
|
|
|
14
15
|
include InjectSql
|
|
15
16
|
include FxHelper
|
|
16
17
|
|
|
17
|
-
class FuncDef < Struct.new(:name, :version, :signature); end
|
|
18
|
-
|
|
19
18
|
source_root File.expand_path("templates", __dir__)
|
|
20
19
|
source_paths << File.expand_path("functions", __dir__)
|
|
21
20
|
|
|
@@ -80,21 +79,7 @@ module Logidze
|
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
def function_definitions
|
|
83
|
-
@function_definitions ||=
|
|
84
|
-
begin
|
|
85
|
-
Dir.glob(File.join(__dir__, "functions", "*.sql")).map do |path|
|
|
86
|
-
name = path.match(/([^\/]+)\.sql/)[1]
|
|
87
|
-
|
|
88
|
-
file = File.open(path)
|
|
89
|
-
header = file.readline
|
|
90
|
-
|
|
91
|
-
version = header.match(/version:\s+(\d+)/)[1].to_i
|
|
92
|
-
parameters = file.readline.match(/CREATE OR REPLACE FUNCTION\s+[\w_]+\((.*)\)/)[1]
|
|
93
|
-
signature = parameters.split(/\s*,\s*/).map { |param| param.split(/\s+/, 2).last.sub(/\s+DEFAULT .*$/, "") }.join(", ")
|
|
94
|
-
|
|
95
|
-
FuncDef.new(name, version, signature)
|
|
96
|
-
end
|
|
97
|
-
end
|
|
82
|
+
@function_definitions ||= Logidze::Utils::FunctionDefinitions.from_fs
|
|
98
83
|
end
|
|
99
84
|
end
|
|
100
85
|
|
|
@@ -35,6 +35,8 @@ module Logidze
|
|
|
35
35
|
class_option :timestamp_column, type: :string, optional: true,
|
|
36
36
|
desc: "Specify timestamp column"
|
|
37
37
|
|
|
38
|
+
class_option :name, type: :string, optional: true, desc: "Migration name"
|
|
39
|
+
|
|
38
40
|
class_option :update, type: :boolean, optional: true,
|
|
39
41
|
desc: "Define whether this is an update migration"
|
|
40
42
|
|
|
@@ -43,7 +45,7 @@ module Logidze
|
|
|
43
45
|
warn "Use only one: --only or --except"
|
|
44
46
|
exit(1)
|
|
45
47
|
end
|
|
46
|
-
migration_template "migration.rb.erb", "db/migrate/#{
|
|
48
|
+
migration_template "migration.rb.erb", "db/migrate/#{migration_name}.rb"
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
def generate_fx_trigger
|
|
@@ -62,6 +64,8 @@ module Logidze
|
|
|
62
64
|
|
|
63
65
|
no_tasks do
|
|
64
66
|
def migration_name
|
|
67
|
+
return options[:name] if options[:name].present?
|
|
68
|
+
|
|
65
69
|
if update?
|
|
66
70
|
"update_logidze_for_#{plural_table_name}"
|
|
67
71
|
else
|
|
@@ -69,8 +73,9 @@ module Logidze
|
|
|
69
73
|
end
|
|
70
74
|
end
|
|
71
75
|
|
|
72
|
-
def
|
|
73
|
-
|
|
76
|
+
def full_table_name
|
|
77
|
+
config = ActiveRecord::Base
|
|
78
|
+
"#{config.table_name_prefix}#{table_name}#{config.table_name_suffix}"
|
|
74
79
|
end
|
|
75
80
|
|
|
76
81
|
def limit
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class <%= @migration_class_name %> < ActiveRecord::Migration[
|
|
1
|
+
class <%= @migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
2
|
def change
|
|
3
3
|
<%- unless update? || only_trigger? -%>
|
|
4
4
|
add_column :<%= table_name %>, :log_data, :jsonb
|
|
@@ -12,14 +12,18 @@ class <%= @migration_class_name %> < ActiveRecord::Migration[5.0]
|
|
|
12
12
|
dir.up do
|
|
13
13
|
<%- if update? -%>
|
|
14
14
|
# Drop legacy trigger if any (<1.0)
|
|
15
|
-
execute
|
|
15
|
+
execute <<~SQL
|
|
16
|
+
DROP TRIGGER IF EXISTS "logidze_on_<%= full_table_name %>" on "<%= full_table_name %>";
|
|
17
|
+
SQL
|
|
16
18
|
|
|
17
19
|
<%- end -%>
|
|
18
20
|
create_trigger :logidze_on_<%= table_name %>, on: :<%= table_name %>
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
dir.down do
|
|
22
|
-
execute
|
|
24
|
+
execute <<~SQL
|
|
25
|
+
DROP TRIGGER IF EXISTS "logidze_on_<%= full_table_name %>" on "<%= full_table_name %>";
|
|
26
|
+
SQL
|
|
23
27
|
end
|
|
24
28
|
end
|
|
25
29
|
<%- end -%>
|
|
@@ -27,7 +31,9 @@ class <%= @migration_class_name %> < ActiveRecord::Migration[5.0]
|
|
|
27
31
|
reversible do |dir|
|
|
28
32
|
dir.up do
|
|
29
33
|
<%- if update? -%>
|
|
30
|
-
execute
|
|
34
|
+
execute <<~SQL
|
|
35
|
+
DROP TRIGGER IF EXISTS "logidze_on_<%= full_table_name %>" on "<%= full_table_name %>";
|
|
36
|
+
SQL
|
|
31
37
|
|
|
32
38
|
<%- end -%>
|
|
33
39
|
execute <<~SQL
|
|
@@ -44,7 +50,9 @@ class <%= @migration_class_name %> < ActiveRecord::Migration[5.0]
|
|
|
44
50
|
# Uncomment this line if you want to raise an error.
|
|
45
51
|
# raise ActiveRecord::IrreversibleMigration
|
|
46
52
|
<%- else -%>
|
|
47
|
-
execute
|
|
53
|
+
execute <<~SQL
|
|
54
|
+
DROP TRIGGER IF EXISTS "logidze_on_<%= full_table_name %>" on "<%= full_table_name %>";
|
|
55
|
+
SQL
|
|
48
56
|
<%- end -%>
|
|
49
57
|
end
|
|
50
58
|
end
|
|
@@ -54,7 +62,7 @@ class <%= @migration_class_name %> < ActiveRecord::Migration[5.0]
|
|
|
54
62
|
reversible do |dir|
|
|
55
63
|
dir.up do
|
|
56
64
|
execute <<~SQL
|
|
57
|
-
UPDATE <%=
|
|
65
|
+
UPDATE "<%= full_table_name %>" as t
|
|
58
66
|
SET log_data = logidze_snapshot(<%= logidze_snapshot_parameters %>);
|
|
59
67
|
SQL
|
|
60
68
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
CREATE TRIGGER
|
|
2
|
-
BEFORE UPDATE OR INSERT ON <%=
|
|
1
|
+
CREATE TRIGGER <%= %Q("logidze_on_#{full_table_name}") %>
|
|
2
|
+
BEFORE UPDATE OR INSERT ON <%= %Q("#{full_table_name}") %> FOR EACH ROW
|
|
3
3
|
WHEN (coalesce(current_setting('logidze.disabled', true), '') <> 'on')
|
|
4
4
|
-- Parameters: history_size_limit (integer), timestamp_column (text), filtered_columns (text[]),
|
|
5
5
|
-- include_columns (boolean), debounce_time_ms (integer)
|
data/lib/logidze/engine.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "logidze"
|
|
4
|
+
require "logidze/utils/check_pending"
|
|
4
5
|
|
|
5
6
|
module Logidze
|
|
6
7
|
class Engine < Rails::Engine # :nodoc:
|
|
@@ -11,5 +12,13 @@ module Logidze
|
|
|
11
12
|
ActiveRecord::Base.send :include, Logidze::HasLogidze
|
|
12
13
|
end
|
|
13
14
|
end
|
|
15
|
+
|
|
16
|
+
initializer "check Logidze function versions" do |app|
|
|
17
|
+
if config.logidze.on_pending_upgrade != :ignore
|
|
18
|
+
ActiveSupport.on_load(:active_record) do
|
|
19
|
+
app.config.app_middleware.use Logidze::Utils::CheckPending
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
14
23
|
end
|
|
15
24
|
end
|
data/lib/logidze/history.rb
CHANGED
|
@@ -48,7 +48,7 @@ module Logidze
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
# Return diff from the initial state to specified time or version.
|
|
51
|
-
# Optional `data`
|
|
51
|
+
# Optional `data` parameter can be used as initial diff state.
|
|
52
52
|
def changes_to(time: nil, version: nil, data: {}, from: 0)
|
|
53
53
|
raise ArgumentError, "Time or version must be specified" if time.nil? && version.nil?
|
|
54
54
|
|
data/lib/logidze/model.rb
CHANGED
|
@@ -213,7 +213,7 @@ module Logidze
|
|
|
213
213
|
|
|
214
214
|
# Loads log_data field from the database, stores to the attributes hash and returns it
|
|
215
215
|
def reload_log_data
|
|
216
|
-
self.log_data = self.class.where(self.class.primary_key => id).pluck("#{self.class.table_name}.log_data").first
|
|
216
|
+
self.log_data = self.class.where(self.class.primary_key => id).pluck("#{self.class.table_name}.log_data".to_sym).first
|
|
217
217
|
end
|
|
218
218
|
|
|
219
219
|
# Nullify log_data column for a single record
|
|
@@ -239,7 +239,7 @@ module Logidze
|
|
|
239
239
|
end
|
|
240
240
|
|
|
241
241
|
def apply_column_diff(column, value)
|
|
242
|
-
return if deleted_column?(column)
|
|
242
|
+
return if deleted_column?(column) || column == "log_data"
|
|
243
243
|
|
|
244
244
|
write_attribute column, deserialize_value(column, value)
|
|
245
245
|
end
|
|
@@ -253,14 +253,8 @@ module Logidze
|
|
|
253
253
|
object_at
|
|
254
254
|
end
|
|
255
255
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
@attributes[column].type.type_cast_from_database(value)
|
|
259
|
-
end
|
|
260
|
-
else
|
|
261
|
-
def deserialize_value(column, value)
|
|
262
|
-
@attributes[column].type.deserialize(value)
|
|
263
|
-
end
|
|
256
|
+
def deserialize_value(column, value)
|
|
257
|
+
@attributes[column].type.deserialize(value)
|
|
264
258
|
end
|
|
265
259
|
|
|
266
260
|
def deleted_column?(column)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "./function_definitions"
|
|
4
|
+
require_relative "./pending_migration_error"
|
|
5
|
+
|
|
6
|
+
module Logidze
|
|
7
|
+
module Utils
|
|
8
|
+
# This Rack middleware is used to verify that all functions are up to date
|
|
9
|
+
class CheckPending
|
|
10
|
+
def initialize(app)
|
|
11
|
+
@app = app
|
|
12
|
+
@needs_check = true
|
|
13
|
+
@mutex = Mutex.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
delegate :connection, to: ActiveRecord::Base
|
|
17
|
+
|
|
18
|
+
def call(env)
|
|
19
|
+
@mutex.synchronize do
|
|
20
|
+
if @needs_check
|
|
21
|
+
notify_or_raise! if needs_migration?
|
|
22
|
+
end
|
|
23
|
+
@needs_check = false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
@app.call(env)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def notify_or_raise!
|
|
32
|
+
case Logidze.on_pending_upgrade
|
|
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."\
|
|
38
|
+
"\n**************************************************\n\n"
|
|
39
|
+
when :raise
|
|
40
|
+
raise Logidze::Utils::PendingMigrationError, "Logidze needs upgrade. Run `bundle exec rails generate logidze:install --update` and apply generated migration."
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def needs_migration?
|
|
45
|
+
(library_function_versions - pg_function_versions).any?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def pg_function_versions
|
|
49
|
+
Logidze::Utils::FunctionDefinitions.from_db.map { |func| [func.name, func.version] }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def library_function_versions
|
|
53
|
+
@library_function_versions ||= Logidze::Utils::FunctionDefinitions.from_fs.map { |func| [func.name, func.version] }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Logidze
|
|
4
|
+
module Utils
|
|
5
|
+
class FuncDef < Struct.new(:name, :version, :signature); end
|
|
6
|
+
|
|
7
|
+
module FunctionDefinitions
|
|
8
|
+
class << self
|
|
9
|
+
def from_fs
|
|
10
|
+
function_paths = Dir.glob(File.join(__dir__, "..", "..", "generators", "logidze", "install", "functions", "*.sql"))
|
|
11
|
+
function_paths.map do |path|
|
|
12
|
+
name = path.match(/([^\/]+)\.sql/)[1]
|
|
13
|
+
|
|
14
|
+
file = File.open(path)
|
|
15
|
+
header, version_comment = file.readline, file.readline
|
|
16
|
+
|
|
17
|
+
signature = parse_signature(header)
|
|
18
|
+
version = parse_version(version_comment)
|
|
19
|
+
FuncDef.new(name, version, signature)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def from_db
|
|
24
|
+
query = <<~SQL
|
|
25
|
+
SELECT pp.proname, pg_get_functiondef(pp.oid) AS definition
|
|
26
|
+
FROM pg_proc pp
|
|
27
|
+
WHERE pp.proname like 'logidze_%'
|
|
28
|
+
ORDER BY pp.oid;
|
|
29
|
+
SQL
|
|
30
|
+
ActiveRecord::Base.connection.execute(query).map do |row|
|
|
31
|
+
version = parse_version(row["definition"])
|
|
32
|
+
FuncDef.new(row["proname"], version, nil)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def parse_version(line)
|
|
39
|
+
line.match(/version:\s+(\d+)/)&.[](1).to_i
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def parse_signature(line)
|
|
43
|
+
parameters = line.match(/CREATE OR REPLACE FUNCTION\s+[\w_]+\((.*)\)/)[1]
|
|
44
|
+
parameters.split(/\s*,\s*/).map { |param| param.split(/\s+/, 2).last.sub(/\s+DEFAULT .*$/, "") }.join(", ")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module Logidze
|
|
6
|
+
module Utils
|
|
7
|
+
class PendingMigrationError < StandardError
|
|
8
|
+
if Rails::VERSION::MAJOR >= 6
|
|
9
|
+
require "active_record"
|
|
10
|
+
require "active_support/actionable_error"
|
|
11
|
+
include ActiveSupport::ActionableError
|
|
12
|
+
|
|
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
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/logidze/version.rb
CHANGED
data/lib/logidze.rb
CHANGED
|
@@ -26,6 +26,8 @@ module Logidze
|
|
|
26
26
|
attr_accessor :ignore_log_data_by_default
|
|
27
27
|
# Whether #at should return self or nil when log_data is nil
|
|
28
28
|
attr_accessor :return_self_if_log_data_is_empty
|
|
29
|
+
# Determines what Logidze should do when upgrade is needed (:raise | :warn | :ignore)
|
|
30
|
+
attr_reader :on_pending_upgrade
|
|
29
31
|
|
|
30
32
|
# Temporary disable DB triggers.
|
|
31
33
|
#
|
|
@@ -35,7 +37,7 @@ module Logidze
|
|
|
35
37
|
with_logidze_setting("logidze.disabled", "on") { yield }
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
#
|
|
40
|
+
# Instruct Logidze to create a full snapshot for the new versions, not a diff
|
|
39
41
|
#
|
|
40
42
|
# @example
|
|
41
43
|
# Logidze.with_full_snapshot { post.touch }
|
|
@@ -43,6 +45,13 @@ module Logidze
|
|
|
43
45
|
with_logidze_setting("logidze.full_snapshot", "on") { yield }
|
|
44
46
|
end
|
|
45
47
|
|
|
48
|
+
def on_pending_upgrade=(mode)
|
|
49
|
+
if %i[raise warn ignore].exclude? mode
|
|
50
|
+
raise ArgumentError, "Unknown on_pending_upgrade option `#{mode.inspect}`. Expecting :raise, :warn or :ignore"
|
|
51
|
+
end
|
|
52
|
+
@on_pending_upgrade = mode
|
|
53
|
+
end
|
|
54
|
+
|
|
46
55
|
private
|
|
47
56
|
|
|
48
57
|
def with_logidze_setting(name, value)
|
|
@@ -59,4 +68,5 @@ module Logidze
|
|
|
59
68
|
self.associations_versioning = false
|
|
60
69
|
self.ignore_log_data_by_default = false
|
|
61
70
|
self.return_self_if_log_data_is_empty = true
|
|
71
|
+
self.on_pending_upgrade = :ignore
|
|
62
72
|
end
|
metadata
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: logidze
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- palkan
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-01-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: railties
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activerecord
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
16
30
|
requirements:
|
|
17
31
|
- - ">="
|
|
@@ -149,6 +163,7 @@ files:
|
|
|
149
163
|
- lib/generators/logidze/fx_helper.rb
|
|
150
164
|
- lib/generators/logidze/inject_sql.rb
|
|
151
165
|
- lib/generators/logidze/install/USAGE
|
|
166
|
+
- lib/generators/logidze/install/functions/logidze_capture_exception.sql
|
|
152
167
|
- lib/generators/logidze/install/functions/logidze_compact_history.sql
|
|
153
168
|
- lib/generators/logidze/install/functions/logidze_filter_keys.sql
|
|
154
169
|
- lib/generators/logidze/install/functions/logidze_logger.sql
|
|
@@ -172,6 +187,9 @@ files:
|
|
|
172
187
|
- lib/logidze/ignore_log_data/cast_attribute_patch.rb
|
|
173
188
|
- lib/logidze/meta.rb
|
|
174
189
|
- lib/logidze/model.rb
|
|
190
|
+
- lib/logidze/utils/check_pending.rb
|
|
191
|
+
- lib/logidze/utils/function_definitions.rb
|
|
192
|
+
- lib/logidze/utils/pending_migration_error.rb
|
|
175
193
|
- lib/logidze/version.rb
|
|
176
194
|
- lib/logidze/versioned_association.rb
|
|
177
195
|
homepage: http://github.com/palkan/logidze
|
|
@@ -183,7 +201,7 @@ metadata:
|
|
|
183
201
|
documentation_uri: http://github.com/palkan/logidze
|
|
184
202
|
homepage_uri: http://github.com/palkan/logidze
|
|
185
203
|
source_code_uri: http://github.com/palkan/logidze
|
|
186
|
-
post_install_message:
|
|
204
|
+
post_install_message:
|
|
187
205
|
rdoc_options: []
|
|
188
206
|
require_paths:
|
|
189
207
|
- lib
|
|
@@ -194,12 +212,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
194
212
|
version: 2.5.0
|
|
195
213
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
214
|
requirements:
|
|
197
|
-
- - "
|
|
215
|
+
- - ">="
|
|
198
216
|
- !ruby/object:Gem::Version
|
|
199
|
-
version:
|
|
217
|
+
version: '0'
|
|
200
218
|
requirements: []
|
|
201
|
-
rubygems_version: 3.
|
|
202
|
-
signing_key:
|
|
219
|
+
rubygems_version: 3.2.22
|
|
220
|
+
signing_key:
|
|
203
221
|
specification_version: 4
|
|
204
222
|
summary: PostgreSQL JSONB-based model changes tracking
|
|
205
223
|
test_files: []
|