fast_versioning 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ec16ba1c62cf76eb3f01b223c8b567084a799353
4
+ data.tar.gz: 6608e3c92443c1839aa47ad671da34e72a0aab40
5
+ SHA512:
6
+ metadata.gz: 15f23487376caa1e310b64ab6397dc5a2ad348c9332a87a7e0303a9bf3477fc57c11fdebad1464ed7f0e0008cffdc9a25969833de10204e7d82bea48023fdb17
7
+ data.tar.gz: 6e7cd07ad4f9e4054b2287deb6e9dc7c42bbc842a4ae1261ce412ebf1477cb7e73fbc9f3b20c6fd28852f23f9f06e785106bad1b0f1ca1d82d309fefdedae815
@@ -0,0 +1,64 @@
1
+ Fast Versioning
2
+ ===========
3
+ A [PaperTrail](https://github.com/airblade/paper_trail) extension for seamless fast key/value versioning of individual object attributes, which can be queried.
4
+
5
+ ### Why?
6
+
7
+ PaperTrail stores version changes in one serialized column, which is great for keeping backups, undoing, etc. For querying and searching this is a real pain to use, and sometimes you need to track single column changes that you can query, use for statistics, quickly check last changes. You can also use Fast Versioning to track more complex object state changes!
8
+
9
+ ### How?
10
+ We hook up to PaperTrail version creation, check if an object's tracked attribute changed and store any changes individually.
11
+
12
+ Installation
13
+ ------------
14
+ 1. Add to the Gemfile and bundle
15
+ ```ruby
16
+ gem 'fast_versioning'
17
+ ```
18
+ 2. Install migrations
19
+ ```shell
20
+ rake fast_versioning:install:migrations
21
+ ```
22
+
23
+ Configuration
24
+ -------------
25
+ 1. Include the concern in your model
26
+
27
+ ```ruby
28
+ include FastVersioning::FastVersioned
29
+ has_paper_trail
30
+
31
+ ...
32
+ # define what you want to track
33
+ has_fast_versions(
34
+ :plan_id,
35
+ :plan_type,
36
+ status: {
37
+ billed_statements: Proc.new { |account| account.utility_statements.count },
38
+ static_value: 'text'
39
+ }
40
+ )
41
+
42
+ # plan_id - is a attribute
43
+ # plan_type - is a custom method
44
+ # status - defines an additional serialized meta apart from storing property change
45
+ ```
46
+
47
+ Usage
48
+ -----
49
+
50
+ ### samples
51
+ ```ruby
52
+ your_model.fast_versions # get all fast versions
53
+ your_model.fast_versions_for(:plan_type) # get fast versions for given property - chain
54
+ your_model.fast_versions.last.version # get parent paper_trail version object
55
+ your_model.fast_versions.last.item # get changed item
56
+ your_model.fast_versions.last.name # property name
57
+ your_model.fast_versions.last.value # get value
58
+ your_model.fast_versions.last.prev_value # get value before the change
59
+
60
+ # query
61
+ your_model.fast_versions_for(:status).where(value: 'active').where(prev_value: 'incomplete')
62
+ ```
63
+
64
+ An [Arcadia Power](http://www.arcadiapower.com) Project
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'FastVersioning'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ require 'bundler/gem_tasks'
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,11 @@
1
+ module FastVersioning
2
+ class FastVersion < ActiveRecord::Base
3
+ belongs_to :item, polymorphic: true
4
+ belongs_to :whodunnit, polymorphic: true
5
+ belongs_to :version, class_name: 'PaperTrail::Version'
6
+
7
+ validates :version_id, uniqueness: { scope: :name }
8
+
9
+ serialize :meta, JSON
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ class CreateFastVersioningFastVersions < ActiveRecord::Migration
2
+ def change
3
+ create_table :fast_versioning_fast_versions do |t|
4
+ t.references :item, polymorphic: true, index: { name: 'fast_version_item_index' }
5
+ t.references :whodunnit, polymorphic: true, index: { name: 'fast_version_whodunnit_index' }
6
+ t.integer :version_id, index: { name: 'fast_version_version_id_index' }
7
+ t.string :name, index: { name: 'fast_version_name_index' }
8
+ t.string :prev_value, index: { name: 'fast_version_prev_value_index' }
9
+ t.string :value, index: { name: 'fast_version_value_index' }
10
+ t.text :meta
11
+ t.datetime :created_at, index: { name: 'fast_version_created_at_index' }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ require 'paper_trail'
2
+ require 'fast_versioning/tracked_attribute'
3
+ require 'fast_versioning/fast_versioned'
4
+ require 'fast_versioning/value_change'
5
+ require 'fast_versioning/paper_trail_extensions'
6
+ require 'fast_versioning/railtie'
7
+ require 'fast_versioning/engine'
8
+
9
+ module FastVersioning
10
+ end
@@ -0,0 +1,5 @@
1
+ module FastVersioning
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace FastVersioning
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ module FastVersioning
2
+ module FastVersioned
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :fast_versions, class_name: 'FastVersioning::FastVersion', as: :item
7
+ end
8
+
9
+ module ClassMethods
10
+ def has_fast_versions(*attributes, **meta)
11
+ define_method :fast_version_for do
12
+ processed_meta = *meta.deep_dup.tap do |item|
13
+ item.values.each do |v|
14
+ v.each { |i,j| v[i] = j.call(self) if j.respond_to?(:call) }
15
+ end
16
+ end
17
+
18
+ (attributes + processed_meta).map do |tracked|
19
+ FastVersioning::TrackedAttribute.new(*tracked)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ def fast_versions_for(name)
26
+ fast_versions.where(name: name)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,38 @@
1
+ module FastVersioning
2
+ module PaperTrailExtensions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ after_create :create_fast_versions
7
+ has_many :fast_versions, class_name: 'FastVersioning::FastVersion'
8
+ end
9
+
10
+ def create_fast_versions
11
+ if item.respond_to?(:fast_version_for, true)
12
+ value_change = FastVersioning::ValueChange.new(version: self)
13
+
14
+ item.send(:fast_version_for).each do |tracked_attribute|
15
+ if value_change.value_was(tracked_attribute.name) != value_change.value_became(tracked_attribute.name)
16
+ fast_versions.create(
17
+ item_id: item_id,
18
+ item_type: item_type,
19
+ whodunnit_id: whodunnit.to_i,
20
+ whodunnit_type: whodunnit_type,
21
+ name: tracked_attribute.name,
22
+ value: value_change.value_became(tracked_attribute.name),
23
+ prev_value: value_change.value_was(tracked_attribute.name),
24
+ meta: tracked_attribute.meta,
25
+ created_at: created_at
26
+ )
27
+ end
28
+ end
29
+ end
30
+ true
31
+ end
32
+
33
+ def recreate_fast_versions!
34
+ fast_versions.destroy_all
35
+ create_fast_versions
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ class FastVersioning::Railtie < Rails::Railtie
2
+ config.to_prepare do
3
+ require 'paper_trail'
4
+
5
+ PaperTrail::Version.module_eval do
6
+ include FastVersioning::PaperTrailExtensions
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module FastVersioning
2
+ class TrackedAttribute
3
+ attr_reader :name, :meta
4
+
5
+ def initialize(name, meta = nil)
6
+ @name = name
7
+ @meta = meta
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ module FastVersioning
2
+ class ValueChange
3
+ def initialize(version:)
4
+ @version = version
5
+ @item = version.item
6
+ end
7
+
8
+ def value_was(name)
9
+ if can_use_changeset?(name)
10
+ @version.changeset[name][0]
11
+ else
12
+ item_was.send(name)
13
+ end
14
+ end
15
+
16
+ def value_became(name)
17
+ if can_use_changeset?(name)
18
+ @version.changeset[name][1]
19
+ else
20
+ item_became.send(name)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def can_use_changeset?(name)
27
+ @version.respond_to?(:changeset) && @version.changeset[name].present?
28
+ end
29
+
30
+ # TODO: support different paper_trail versions
31
+ def item_was
32
+ @item_was ||= @version.reify(dup: true) || @item.class.new
33
+ end
34
+
35
+ # TODO: support different paper_trail versions
36
+ def item_became
37
+ @item_became ||= @version.next.present? ? @version.next.reify(dup: true) : @item
38
+ end
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fast_versioning
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Arcadia Power
8
+ - Iwo Dziechciarow
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-09-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: paper_trail
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '4.2'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '4.2'
42
+ - !ruby/object:Gem::Dependency
43
+ name: sqlite3
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec-rails
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ description: Fast versioning extension for paper_trail
71
+ email:
72
+ - engineering@arcadiapower.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - README.md
78
+ - Rakefile
79
+ - app/models/fast_versioning/fast_version.rb
80
+ - db/migrate/20160914161314_create_fast_versioning_fast_versions.rb
81
+ - lib/fast_versioning.rb
82
+ - lib/fast_versioning/engine.rb
83
+ - lib/fast_versioning/fast_versioned.rb
84
+ - lib/fast_versioning/paper_trail_extensions.rb
85
+ - lib/fast_versioning/railtie.rb
86
+ - lib/fast_versioning/tracked_attribute.rb
87
+ - lib/fast_versioning/value_change.rb
88
+ homepage: https://github.com/ArcadiaPower/fast-versioning
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.5.1
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: Fast versioning extension for paper_trail
112
+ test_files: []