logidze 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +16 -10
- 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 +1 -1
- data/lib/generators/logidze/install/functions/logidze_snapshot.sql +9 -1
- data/lib/generators/logidze/install/functions/logidze_version.sql +1 -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/templates/migration.rb.erb +1 -1
- data/lib/logidze.rb +11 -1
- data/lib/logidze/engine.rb +9 -0
- 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
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6c441d5e6e60ef695eb354e4bfb5be9fa182bd8b70755d829aee6eb2781e401
|
4
|
+
data.tar.gz: d64374a0d6327f2f713fd7341c31de93472f32d045cb5c825c35874c756307d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3f453e410de263ed8b0704aece35e6274dfc19c9074a8f75450e84033318b149ae81c9e1f48cc9d515e523b95c98c14cbd3453a7c41db1690febfe8060f640d
|
7
|
+
data.tar.gz: dbf4a22b357889bc0d2aaeda52bffc8bc245cdc12d2cb34d0f7c9ccec7c0f60807ecc3cbd5272fee567420024309f8be05f6e1e8c9f45334ab3d2ad155a97a12
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## master (unreleased)
|
4
|
+
|
5
|
+
## 1.1.0 (2021-03-31)
|
6
|
+
|
7
|
+
- Add pending upgrade checks [Experimental]. ([@skryukov][])
|
8
|
+
|
9
|
+
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.
|
10
|
+
|
11
|
+
- [Fixes [#171](https://github.com/palkan/logidze/issues/171)] Stringify jsonb column values within snapshots. ([@skryukov][])
|
12
|
+
|
13
|
+
- [Fixes [#175](https://github.com/palkan/logidze/issues/175)] Set dynamic ActiveRecord version for migrations. ([@skryukov][])
|
14
|
+
|
15
|
+
- [Fixes [#184](https://github.com/palkan/logidze/issues/184)] Remove Rails meta-gem dependency ([@bf4][])
|
16
|
+
|
3
17
|
## 1.0.0 (2020-11-09)
|
4
18
|
|
5
19
|
- Add `--name` option to model generator to specify the migration name. ([@palkan][])
|
@@ -332,3 +346,4 @@ This is a quick fix for a more general problem (see [#59](https://github.com/pal
|
|
332
346
|
[@zocoi]: https://github.com/zocoi
|
333
347
|
[@duderman]: https://github.com/duderman
|
334
348
|
[@oleg-kiviljov]: https://github.com/oleg-kiviljov
|
349
|
+
[@skryukov]: https://github.com/skryukov
|
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
|
@@ -22,16 +22,16 @@ Other requirements:
|
|
22
22
|
|
23
23
|
## Links
|
24
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)
|
25
26
|
- [Logidze: for all those tired of versioning data](https://evilmartians.com/chronicles/introducing-logidze?utm_source=logidze)
|
26
27
|
|
27
28
|
## Table of contents
|
28
29
|
|
29
|
-
- [Main concepts](#main-concepts)
|
30
30
|
- [Installation & Configuration](#installation)
|
31
31
|
- [Using with schema.rb](#using-with-schemarb)
|
32
32
|
- [Configuring models](#configuring-models)
|
33
33
|
- [Backfill data](#backfill-data)
|
34
|
-
- [Log size
|
34
|
+
- [Log size limits](#log-size-limits)
|
35
35
|
- [Tracking only selected columns](#tracking-only-selected-columns)
|
36
36
|
- [Logs timestamps](#logs-timestamps)
|
37
37
|
- [Usage](#usage)
|
@@ -439,7 +439,7 @@ See also the discussion: [#61](https://github.com/palkan/logidze/issues/61).
|
|
439
439
|
We try to make an upgrade process as simple as possible. For now, the only required action is to create and run a migration:
|
440
440
|
|
441
441
|
```sh
|
442
|
-
rails generate logidze:install --update
|
442
|
+
bundle exec rails generate logidze:install --update
|
443
443
|
```
|
444
444
|
|
445
445
|
This updates core `logdize_logger` DB function. No need to update tables or triggers.
|
@@ -449,31 +449,37 @@ This updates core `logdize_logger` DB function. No need to update tables or trig
|
|
449
449
|
If you want to update Logidze settings for the model, run migration with `--update` flag:
|
450
450
|
|
451
451
|
```sh
|
452
|
-
rails generate logidze:model Post --update --only=title,body,rating
|
452
|
+
bundle exec rails generate logidze:model Post --update --only=title,body,rating
|
453
453
|
```
|
454
454
|
|
455
455
|
You can also use the `--name` option to specify the migration name to avoid duplicate migration names:
|
456
456
|
|
457
457
|
```sh
|
458
|
-
$ rails generate logidze:model Post --update --only=title,body,rating --name add_only_filter_to_posts_log_data
|
458
|
+
$ bundle exec rails generate logidze:model Post --update --only=title,body,rating --name add_only_filter_to_posts_log_data
|
459
459
|
|
460
460
|
create db/migrate/20202309142344_add_only_filter_to_posts_log_data.rb
|
461
461
|
```
|
462
462
|
|
463
|
+
### Pending upgrade check [Experimental]
|
464
|
+
|
465
|
+
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.
|
466
|
+
|
463
467
|
### Upgrading from 0.x to 1.0 (edge)
|
464
468
|
|
465
469
|
#### Schema and migrations
|
466
470
|
|
467
|
-
Most SQL
|
471
|
+
Most SQL function definitions have changed without backward compatibility.
|
468
472
|
Perform the following steps to upgrade:
|
469
473
|
|
470
|
-
1. Re-install Logidze: `rails generate logidze:install --update`.
|
474
|
+
1. Re-install Logidze: `bundle exec rails generate logidze:install --update`.
|
475
|
+
|
476
|
+
1. Re-install Logidze triggers **for all models**: `bundle exec rails generate logidze:model <model> --update`.
|
471
477
|
|
472
|
-
|
478
|
+
**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.
|
473
479
|
|
474
480
|
1. Remove the `include Logidze::Migration` line from the old migration files (if any)—this module has been removed.
|
475
481
|
|
476
|
-
Rewrite
|
482
|
+
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).
|
477
483
|
|
478
484
|
#### API changes
|
479
485
|
|
@@ -1,7 +1,8 @@
|
|
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: 2
|
3
3
|
DECLARE
|
4
4
|
ts timestamp with time zone;
|
5
|
+
k text;
|
5
6
|
BEGIN
|
6
7
|
IF ts_column IS NULL THEN
|
7
8
|
ts := statement_timestamp();
|
@@ -13,6 +14,13 @@ CREATE OR REPLACE FUNCTION logidze_snapshot(item jsonb, ts_column text DEFAULT N
|
|
13
14
|
item := logidze_filter_keys(item, columns, include_columns);
|
14
15
|
END IF;
|
15
16
|
|
17
|
+
FOR k IN (SELECT key FROM jsonb_each(item))
|
18
|
+
LOOP
|
19
|
+
IF jsonb_typeof(item->k) = 'object' THEN
|
20
|
+
item := jsonb_set(item, ARRAY[k], to_jsonb(item->>k));
|
21
|
+
END IF;
|
22
|
+
END LOOP;
|
23
|
+
|
16
24
|
return json_build_object(
|
17
25
|
'v', 1,
|
18
26
|
'h', jsonb_build_array(
|
@@ -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
|
|
@@ -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
|
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
|
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
|
@@ -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
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.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-31 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
|
- - ">="
|
@@ -172,6 +186,9 @@ files:
|
|
172
186
|
- lib/logidze/ignore_log_data/cast_attribute_patch.rb
|
173
187
|
- lib/logidze/meta.rb
|
174
188
|
- lib/logidze/model.rb
|
189
|
+
- lib/logidze/utils/check_pending.rb
|
190
|
+
- lib/logidze/utils/function_definitions.rb
|
191
|
+
- lib/logidze/utils/pending_migration_error.rb
|
175
192
|
- lib/logidze/version.rb
|
176
193
|
- lib/logidze/versioned_association.rb
|
177
194
|
homepage: http://github.com/palkan/logidze
|