logidze 1.0.0.rc1 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Cult Of Martians](http://cultofmartians.com/assets/badges/badge.svg)](http://cultofmartians.com)
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/logidze.svg)](https://rubygems.org/gems/logidze)
|
3
|
-
![Build](https://github.com/palkan/logidze/workflows/Build/badge.svg)
|
3
|
+
[![Build](https://github.com/palkan/logidze/workflows/Build/badge.svg)](https://github.com/palkan/logidze/actions)
|
4
4
|
[![Open Source Helpers](https://www.codetriage.com/palkan/logidze/badges/users.svg)](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: []
|