logidze 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +3 -0
  3. data/.github/ISSUE_TEMPLATE.md +20 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +29 -0
  5. data/.rubocop.yml +30 -69
  6. data/.travis.yml +8 -5
  7. data/CHANGELOG.md +35 -1
  8. data/Gemfile +2 -0
  9. data/LICENSE.txt +1 -1
  10. data/README.md +67 -26
  11. data/Rakefile +2 -2
  12. data/assets/pg_log_data_chart.png +0 -0
  13. data/bench/performance/README.md +2 -2
  14. data/bench/performance/diff_bench.rb +15 -13
  15. data/bench/performance/insert_bench.rb +6 -4
  16. data/bench/performance/memory_profile.rb +12 -9
  17. data/bench/performance/setup.rb +35 -28
  18. data/bench/performance/update_bench.rb +8 -6
  19. data/bin/setup +2 -2
  20. data/gemfiles/rails42.gemfile +1 -0
  21. data/gemfiles/rails6.gemfile +6 -0
  22. data/lib/generators/logidze/install/install_generator.rb +3 -2
  23. data/lib/generators/logidze/model/model_generator.rb +12 -12
  24. data/lib/logidze.rb +44 -18
  25. data/lib/logidze/engine.rb +2 -1
  26. data/lib/logidze/has_logidze.rb +14 -4
  27. data/lib/logidze/history.rb +6 -5
  28. data/lib/logidze/history/type.rb +1 -1
  29. data/lib/logidze/history/version.rb +6 -5
  30. data/lib/logidze/ignore_log_data.rb +31 -4
  31. data/lib/logidze/ignore_log_data/association.rb +11 -0
  32. data/lib/logidze/ignore_log_data/default_scope_patch.rb +25 -0
  33. data/lib/logidze/ignore_log_data/ignored_columns.rb +1 -1
  34. data/lib/logidze/ignore_log_data/missing_attribute_patch.rb +3 -1
  35. data/lib/logidze/meta.rb +1 -1
  36. data/lib/logidze/migration.rb +1 -0
  37. data/lib/logidze/model.rb +14 -4
  38. data/lib/logidze/version.rb +2 -1
  39. data/lib/logidze/versioned_association.rb +0 -1
  40. data/logidze.gemspec +16 -8
  41. metadata +28 -60
  42. data/.hound.yml +0 -3
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require "bundler/gem_tasks"
2
+
3
3
  require "rspec/core/rake_task"
4
4
  require "rubocop/rake_task"
5
5
 
@@ -25,4 +25,4 @@ RSpec::Core::RakeTask.new("spec:acceptance") do |task|
25
25
  end
26
26
 
27
27
  desc "Run the specs and acceptance tests"
28
- task default: %w(rubocop spec spec:acceptance)
28
+ task default: %w[rubocop spec spec:acceptance]
Binary file
@@ -17,14 +17,14 @@ When changeset has 2 fields:
17
17
 
18
18
  ```
19
19
  PaperTrail UPDATE #1 256.651 (±26.5%) i/s - 1.206k in 5.002300s
20
- Logidze UPDATE #1 356.932 (±12.6%) i/s - 1.764k in 5.030560s
20
+ Logidze UPDATE #1 356.932 (±12.6%) i/s - 1.764k in 5.030560s
21
21
  ```
22
22
 
23
23
  When changeset has 5 fields:
24
24
 
25
25
  ```
26
26
  PaperTrail UPDATE #2 246.281 (±24.0%) i/s - 1.168k in 5.008234s
27
- Logidze UPDATE #2 331.942 (±16.6%) i/s - 1.593k in 5.028135s
27
+ Logidze UPDATE #2 331.942 (±16.6%) i/s - 1.593k in 5.028135s
28
28
  ```
29
29
 
30
30
  ## Getting diff ([source](diff_bench.rb))
@@ -1,36 +1,38 @@
1
- require 'benchmark/ips'
2
- require './setup'
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark/ips"
4
+ require "./setup"
3
5
 
4
6
  # How many records do you want?
5
- N = (ENV['N'] || '100').to_i
7
+ N = (ENV["N"] || "100").to_i
6
8
 
7
9
  # How many version each record has?
8
- V = (ENV['V'] || '10').to_i
10
+ V = (ENV["V"] || "10").to_i
9
11
 
10
12
  # Benchmark run time
11
- BM_TIME = (ENV['BM_TIME'] || 5).to_i
13
+ BM_TIME = (ENV["BM_TIME"] || 5).to_i
12
14
 
13
15
  BM_WARMUP = [(BM_TIME / 10), 2].max
14
16
 
15
17
  LogidzeBench.cleanup
16
18
  LogidzeBench.populate(N)
17
19
 
18
- ts1 = LogidzeBench.generate_versions(V/2)
20
+ ts1 = LogidzeBench.generate_versions(V / 2)
19
21
 
20
- LogidzeBench.generate_versions(V/2)
22
+ LogidzeBench.generate_versions(V / 2)
21
23
 
22
24
  Benchmark.ips do |x|
23
25
  x.config(time: BM_TIME, warmup: BM_WARMUP)
24
26
 
25
- x.report('PT DIFF') do
26
- User.random(N/2).diff_from(ts1)
27
+ x.report("PT DIFF") do
28
+ User.random(N / 2).diff_from(ts1)
27
29
  end
28
30
 
29
- x.report('PT (join) DIFF') do
30
- User.random(N/2).diff_from_joined(ts1)
31
+ x.report("PT (join) DIFF") do
32
+ User.random(N / 2).diff_from_joined(ts1)
31
33
  end
32
34
 
33
- x.report('Logidze DIFF') do
34
- LogidzeUser.random(N/2).diff_from(ts1)
35
+ x.report("Logidze DIFF") do
36
+ LogidzeUser.random(N / 2).diff_from(ts1)
35
37
  end
36
38
  end
@@ -1,5 +1,7 @@
1
- require 'benchmark/ips'
2
- require './setup'
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark/ips"
4
+ require "./setup"
3
5
 
4
6
  params = {
5
7
  email: Faker::Internet.email,
@@ -10,11 +12,11 @@ params = {
10
12
  }
11
13
 
12
14
  Benchmark.ips do |x|
13
- x.report('PaperTrail INSERT') do
15
+ x.report("PaperTrail INSERT") do
14
16
  User.create!(params)
15
17
  end
16
18
 
17
- x.report('Logidze INSERT') do
19
+ x.report("Logidze INSERT") do
18
20
  LogidzeUser.create!(params)
19
21
  end
20
22
  end
@@ -1,12 +1,14 @@
1
- require './setup'
2
- require 'active_support/core_ext'
3
- require 'memory_profiler'
1
+ # frozen_string_literal: true
2
+
3
+ require "./setup"
4
+ require "active_support/core_ext"
5
+ require "memory_profiler"
4
6
 
5
7
  # How many records do you want?
6
- N = (ENV['N'] || '10').to_i
8
+ N = (ENV["N"] || "10").to_i
7
9
 
8
10
  # How many version each record has?
9
- V = (ENV['V'] || '10').to_i
11
+ V = (ENV["V"] || "10").to_i
10
12
 
11
13
  LogidzeBench.cleanup
12
14
  LogidzeBench.populate(N)
@@ -17,6 +19,7 @@ module MemoryReport
17
19
  MEGA_BYTE = 1024 * 1024
18
20
 
19
21
  module_function
22
+
20
23
  def call(msg, relation)
21
24
  buffer = nil
22
25
  delta = N / 10
@@ -36,6 +39,7 @@ module MemoryReport
36
39
  end
37
40
 
38
41
  module_function
42
+
39
43
  def to_human_size(size)
40
44
  if size > MEGA_BYTE
41
45
  "#{(size.to_f / MEGA_BYTE).round(2)} MB"
@@ -47,7 +51,6 @@ module MemoryReport
47
51
  end
48
52
  end
49
53
 
50
-
51
- MemoryReport.("PT records", User.all)
52
- MemoryReport.("PT with versions", User.joins(:versions).all)
53
- MemoryReport.("Logidze records", LogidzeUser.all)
54
+ MemoryReport.call("PT records", User.all)
55
+ MemoryReport.call("PT with versions", User.joins(:versions).all)
56
+ MemoryReport.call("Logidze records", LogidzeUser.all)
@@ -1,22 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
- require 'bundler/inline'
4
+ require "bundler/inline"
3
5
  rescue LoadError => e
4
- $stderr.puts 'Bundler version 1.10 or later is required. Please update your Bundler'
6
+ warn "Bundler version 1.10 or later is required. Please update your Bundler"
5
7
  raise e
6
8
  end
7
9
 
8
10
  gemfile(true) do
9
- source 'https://rubygems.org'
10
- gem 'activerecord', '~>4.2'
11
- gem 'pg'
12
- gem 'paper_trail', '~>4.2', require: false
13
- gem 'pry-byebug'
14
- gem 'faker'
15
- gem 'benchmark-ips'
16
- gem 'memory_profiler'
11
+ source "https://rubygems.org"
12
+ gem "activerecord", "~>4.2"
13
+ gem "pg"
14
+ gem "paper_trail", "~>4.2", require: false
15
+ gem "pry-byebug"
16
+ gem "faker"
17
+ gem "benchmark-ips"
18
+ gem "memory_profiler"
17
19
  end
18
20
 
19
- DB_NAME = ENV['DB_NAME'] || 'logidze_query_bench'
21
+ DB_NAME = ENV["DB_NAME"] || "logidze_query_bench"
20
22
 
21
23
  begin
22
24
  system("createdb #{DB_NAME}")
@@ -24,24 +26,25 @@ rescue
24
26
  $stdout.puts "DB already exists"
25
27
  end
26
28
 
27
- $LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
29
+ $LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
28
30
 
29
- require 'active_record'
30
- require 'logger'
31
- require 'logidze'
31
+ require "active_record"
32
+ require "logger"
33
+ require "logidze"
32
34
 
33
35
  ActiveRecord::Base.send :include, Logidze::HasLogidze
34
36
 
35
- ActiveRecord::Base.establish_connection(adapter: 'postgresql', database: DB_NAME)
37
+ ActiveRecord::Base.establish_connection(adapter: "postgresql", database: DB_NAME)
36
38
 
37
39
  at_exit do
38
40
  ActiveRecord::Base.connection.disconnect!
39
41
  end
40
42
 
41
- require 'paper_trail'
43
+ require "paper_trail"
42
44
 
43
45
  module LogidzeBench
44
46
  module_function
47
+
45
48
  def setup_db
46
49
  ActiveRecord::Schema.define do
47
50
  # PaperTrail setup
@@ -171,7 +174,7 @@ module LogidzeBench
171
174
  jsonb_set(
172
175
  NEW.log_data->'h',
173
176
  '{1}',
174
- merged
177
+ merged
175
178
  ) - 0
176
179
  );
177
180
  END IF;
@@ -198,7 +201,7 @@ module LogidzeBench
198
201
  t.string :name
199
202
  t.text :bio
200
203
  t.integer :age
201
- t.jsonb :log_data, default: '{}', null: false
204
+ t.jsonb :log_data, default: "{}", null: false
202
205
  t.timestamps
203
206
  end
204
207
 
@@ -212,6 +215,7 @@ module LogidzeBench
212
215
  end
213
216
 
214
217
  module_function
218
+
215
219
  def populate(n = 1_000)
216
220
  n.times do
217
221
  params = fake_params
@@ -221,6 +225,7 @@ module LogidzeBench
221
225
  end
222
226
 
223
227
  module_function
228
+
224
229
  def cleanup
225
230
  LogidzeUser.delete_all
226
231
  User.delete_all
@@ -228,8 +233,9 @@ module LogidzeBench
228
233
  end
229
234
 
230
235
  module_function
236
+
231
237
  def generate_versions(num = 1)
232
- num.times do
238
+ num.times do
233
239
  User.find_each do |u|
234
240
  u.update!(fake_params(sample: true))
235
241
  end
@@ -245,6 +251,7 @@ module LogidzeBench
245
251
  end
246
252
 
247
253
  module_function
254
+
248
255
  def fake_params(sample: false)
249
256
  params = {
250
257
  email: Faker::Internet.email,
@@ -254,14 +261,14 @@ module LogidzeBench
254
261
  bio: Faker::Lorem.paragraph
255
262
  }
256
263
 
257
- return params.slice(%i(email position name age bio).sample) if sample
264
+ return params.slice(%i[email position name age bio].sample) if sample
258
265
  params
259
266
  end
260
267
  end
261
268
 
262
269
  module ARandom
263
270
  def random(num = 1)
264
- rel = order('random()')
271
+ rel = order("random()")
265
272
  num == 1 ? rel.first : rel.limit(num)
266
273
  end
267
274
  end
@@ -271,11 +278,11 @@ class User < ActiveRecord::Base
271
278
  has_paper_trail
272
279
 
273
280
  def self.diff_from(ts)
274
- includes(:versions).map { |u| { 'id' => u.id, 'changes' => u.diff_from(ts) } }
281
+ includes(:versions).map { |u| {"id" => u.id, "changes" => u.diff_from(ts)} }
275
282
  end
276
283
 
277
284
  def self.diff_from_joined(ts)
278
- eager_load(:versions).map { |u| { 'id' => u.id, 'changes' => u.diff_from(ts) } }
285
+ eager_load(:versions).map { |u| {"id" => u.id, "changes" => u.diff_from(ts)} }
279
286
  end
280
287
 
281
288
  def diff_from(ts)
@@ -290,11 +297,11 @@ class User < ActiveRecord::Base
290
297
  private
291
298
 
292
299
  def merge_changeset(acc, data)
293
- data.each do |k,v|
300
+ data.each do |k, v|
294
301
  unless acc.key?(k)
295
- acc[k] = { 'old' => v[0] }
302
+ acc[k] = {"old" => v[0]}
296
303
  end
297
- acc[k]['new'] = v[1]
304
+ acc[k]["new"] = v[1]
298
305
  end
299
306
  end
300
307
  end
@@ -305,4 +312,4 @@ class LogidzeUser < ActiveRecord::Base
305
312
  end
306
313
 
307
314
  # Run migration only if neccessary
308
- LogidzeBench.setup_db if ENV['FORCE'].present? || !ActiveRecord::Base.connection.tables.include?('logidze_users')
315
+ LogidzeBench.setup_db if ENV["FORCE"].present? || !ActiveRecord::Base.connection.tables.include?("logidze_users")
@@ -1,5 +1,7 @@
1
- require 'benchmark/ips'
2
- require './setup'
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark/ips"
4
+ require "./setup"
3
5
 
4
6
  params = {
5
7
  age: Faker::Number.number(2),
@@ -18,19 +20,19 @@ LogidzeBench.cleanup
18
20
  LogidzeBench.populate
19
21
 
20
22
  Benchmark.ips do |x|
21
- x.report('PT UPDATE #1') do
23
+ x.report("PT UPDATE #1") do
22
24
  User.random.update!(params)
23
25
  end
24
26
 
25
- x.report('Logidze UPDATE #1') do
27
+ x.report("Logidze UPDATE #1") do
26
28
  LogidzeUser.random.update!(params)
27
29
  end
28
30
 
29
- x.report('PT UPDATE #2') do
31
+ x.report("PT UPDATE #2") do
30
32
  User.random.update!(params2)
31
33
  end
32
34
 
33
- x.report('Logidze UPDATE #2') do
35
+ x.report("Logidze UPDATE #2") do
34
36
  LogidzeUser.random.update!(params2)
35
37
  end
36
38
  end
data/bin/setup CHANGED
@@ -5,5 +5,5 @@ set -e
5
5
  gem install bundler --conservative
6
6
  bundle check || bundle install
7
7
 
8
- bundle exec rake dummy:db:create
9
- bundle exec rake dummy:db:test:prepare
8
+ RAILS_ENV=test bundle exec rake dummy:db:create
9
+ RAILS_ENV=test bundle exec rake dummy:db:migrate
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'rails', '~> 4.2'
4
+ gem 'pg', '~> 0.18'
4
5
 
5
6
  gemspec path: '..'
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '6.0.0.rc1'
4
+ gem 'rspec-rails', '>= 3.5'
5
+
6
+ gemspec path: '..'
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "rails/generators"
3
4
  require "rails/generators/active_record"
4
5
 
@@ -7,7 +8,7 @@ module Logidze
7
8
  class InstallGenerator < ::Rails::Generators::Base # :nodoc:
8
9
  include Rails::Generators::Migration
9
10
 
10
- source_root File.expand_path('templates', __dir__)
11
+ source_root File.expand_path("templates", __dir__)
11
12
 
12
13
  class_option :update, type: :boolean, optional: true,
13
14
  desc: "Define whether this is an update migration"
@@ -25,7 +26,7 @@ module Logidze
25
26
  no_tasks do
26
27
  def migration_name
27
28
  if update?
28
- "logidze_update_#{Logidze::VERSION.delete('.')}"
29
+ "logidze_update_#{Logidze::VERSION.delete(".")}"
29
30
  else
30
31
  "logidze_install"
31
32
  end
@@ -1,12 +1,12 @@
1
- # rubocop:disable Metrics/BlockLength
2
1
  # frozen_string_literal: true
2
+
3
3
  require "rails/generators"
4
4
  require "rails/generators/active_record/migration/migration_generator"
5
5
 
6
6
  module Logidze
7
7
  module Generators
8
8
  class ModelGenerator < ::ActiveRecord::Generators::Base # :nodoc:
9
- source_root File.expand_path('templates', __dir__)
9
+ source_root File.expand_path("templates", __dir__)
10
10
 
11
11
  class_option :limit, type: :numeric, optional: true, desc: "Specify history size limit"
12
12
 
@@ -77,17 +77,17 @@ module Logidze
77
77
 
78
78
  def columns_blacklist
79
79
  array = if !options[:whitelist]
80
- options[:blacklist]
81
- else
82
- class_name.constantize.column_names - options[:whitelist]
83
- end
80
+ options[:blacklist]
81
+ else
82
+ class_name.constantize.column_names - options[:whitelist]
83
+ end
84
84
 
85
85
  format_pgsql_array(array)
86
86
  end
87
87
 
88
88
  def timestamp_column
89
- value = options[:timestamp_column] || 'updated_at'
90
- return if %w(nil null false).include?(value)
89
+ value = options[:timestamp_column] || "updated_at"
90
+ return if %w[nil null false].include?(value)
91
91
 
92
92
  escape_pgsql_string(value)
93
93
  end
@@ -101,13 +101,13 @@ module Logidze
101
101
  end
102
102
 
103
103
  def logidze_snapshot_parameters
104
- format_pgsql_args('to_jsonb(t)', timestamp_column, columns_blacklist)
104
+ format_pgsql_args("to_jsonb(t)", timestamp_column, columns_blacklist)
105
105
  end
106
106
 
107
107
  def format_pgsql_array(ruby_array)
108
108
  return if ruby_array.blank?
109
109
 
110
- "'{" + ruby_array.join(', ') + "}'"
110
+ "'{" + ruby_array.join(", ") + "}'"
111
111
  end
112
112
 
113
113
  def escape_pgsql_string(string)
@@ -124,10 +124,10 @@ module Logidze
124
124
  def format_pgsql_args(*values)
125
125
  args = []
126
126
  values.reverse_each do |value|
127
- formatted_value = value.presence || (args.any? && 'null')
127
+ formatted_value = value.presence || (args.any? && "null")
128
128
  args << formatted_value if formatted_value
129
129
  end
130
- args.compact.reverse.join(', ')
130
+ args.compact.reverse.join(", ")
131
131
  end
132
132
  end
133
133