saseo 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 365c9551971dcd5e511dd8bfceffbf60ead36c2f
4
- data.tar.gz: 3cee7c15a02815d3c9fea3c92d6d85d61c21cd7c
3
+ metadata.gz: b329bf7dd271331dda62ef081a05d9f7e0c64af9
4
+ data.tar.gz: ed09bc9155ee23828beee19b3fa32e0c781307e5
5
5
  SHA512:
6
- metadata.gz: 78ffd353c6977bba243eceed9794711449d62a0df65b593bbf25005eb41da2cde0e591f4ff65e070628dba305d2b0d9dbb7135ec111af721156b80a402bffc7a
7
- data.tar.gz: e3f4d6356a9c3b117bc9e1eccc301e1456a1035612c2e5f590f1cba8fe2493ece7ef28fde3ee577854f0dcb67ab56f0a88bd0f1faca4af32dd18b7d94a96b1af
6
+ metadata.gz: 993d46fb9c8d728324a334c627bdfefae21d53668d9c431bc615bd343370d04ea3c0636e83ecb1cc15d6014232498acaf5e26765c4e3410b67334e670e5ace9f
7
+ data.tar.gz: 8c270a1382502571d728940c10509d00f5f8a18c4d0bcb181b11088fe98180d08d259d112b3ebbab4be463491b6ac9ae526235e846b814ac34bc97a9f23db8ce
data/README.md CHANGED
@@ -5,6 +5,9 @@ RabbitMQ based PaperTrail replacement
5
5
  [![Dependency Status](https://gemnasium.com/avantcredit/saseo.svg)](https://gemnasium.com/avantcredit/saseo)
6
6
  [![Code Climate](https://codeclimate.com/github/avantcredit/saseo/badges/gpa.svg)](https://codeclimate.com/github/avantcredit/saseo)
7
7
  [![Test Coverage](https://codeclimate.com/github/avantcredit/saseo/badges/coverage.svg)](https://codeclimate.com/github/avantcredit/saseo)
8
+ [![Gem Version](http://img.shields.io/gem/v/saseo.svg)](https://rubygems.org/gems/saseo)
9
+ [![License](http://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org)
10
+
8
11
 
9
12
  ## Installation
10
13
 
@@ -26,6 +29,8 @@ Or install it yourself as:
26
29
 
27
30
  TODO: Write usage instructions here
28
31
 
32
+ ## Sample Setup
33
+ ![](https://raw.githubusercontent.com/avantcredit/saseo/master/sample_saseo_setup.png)
29
34
  ## Development
30
35
 
31
36
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -30,10 +30,6 @@ module Saseo
30
30
  load_config(config[env])
31
31
  end
32
32
 
33
- def channels
34
- @channels ||= _load_json_config :channels
35
- end
36
-
37
33
  def consumer_philotic_subscription
38
34
  @consumer_philotic_subscription ||= _load_json_config :consumer_philotic_subscription
39
35
  end
@@ -11,6 +11,7 @@ module Saseo
11
11
  SOURCE_TABLE_SCHEMA = 'saseo'
12
12
  SOURCE_TABLE_NAME = 'saseo_source_versions'
13
13
  CONSUMER_PHILOTIC_SUBSCRIPTION = 'saseo_audit'
14
+ IGNORE_FIELDS_CONFIG_PATH = nil
14
15
 
15
16
  def defaults
16
17
  @defaults ||= Hash[Saseo::Config::Defaults.constants.map do |c|
@@ -32,7 +32,7 @@ module Saseo
32
32
  end
33
33
 
34
34
  def database_config_from_load_path
35
- config = nil
35
+ config = nil
36
36
  config_path = database_config_path
37
37
  $:.each do |load_path|
38
38
  begin
@@ -43,9 +43,44 @@ module Saseo
43
43
  end
44
44
  config
45
45
  end
46
+
47
+ def reconnect!
48
+ ActiveRecord::Base.clear_all_connections!
49
+ ActiveRecord::Base.establish_connection
50
+ end
46
51
  end
47
52
 
53
+ validates :transaction_id, presence: true
54
+ validates :table_name, presence: true
55
+ validates :action_timestamp, presence: true
56
+ validates :action, presence: true, inclusion: {in: %w[INSERT UPDATE DELETE]}
57
+ validates :whodunnit, presence: true
58
+ validates :old_data, presence: true, unless: ->(version) { version.new_data.present? }
59
+ validates :new_data, presence: true, unless: ->(version) { version.old_data.present? }
60
+
61
+ validate :validate_has_changes
62
+
48
63
  establish_connection database_config
64
+
65
+ def changes
66
+ old_keys = old_data ? old_data.keys : []
67
+ new_keys = new_data ? new_data.keys : []
68
+ (old_keys | new_keys).reduce({}) do |changes, key|
69
+ old_value = old_data ? old_data[key] : nil
70
+ new_value = new_data ? new_data[key] : nil
71
+ changes[key] = [old_value, new_value] if old_value != new_value
72
+ changes
73
+ end
74
+ end
75
+
76
+ def has_changes?
77
+ changes.any?
78
+ end
79
+
80
+ private
81
+ def validate_has_changes
82
+ errors.add(:new_data, 'can not be the same as old_data') unless has_changes?
83
+ end
49
84
  end
50
85
  end
51
86
  end
@@ -6,14 +6,6 @@ module Saseo
6
6
  module Source
7
7
  class Version < Saseo::Models::Source::Base
8
8
  self.table_name = "#{Saseo.config.source_table_schema}.#{Saseo.config.source_table_name}"
9
-
10
- validates :transaction_id, presence: true
11
- validates :table_name, presence: true
12
- validates :action_timestamp, presence: true
13
- validates :action, presence: true, inclusion: {in: %w[INSERT UPDATE DELETE]}
14
- validates :whodunnit, presence: true
15
- validates :old_data, presence: true, unless: ->(version) { version.new_data.present? }
16
- validates :new_data, presence: true, unless: ->(version) { version.old_data.present? }
17
9
  end
18
10
  end
19
11
  end
@@ -5,14 +5,6 @@ module Saseo
5
5
  module Models
6
6
  class Version < Saseo::Models::Base
7
7
  self.table_name = Saseo.config.table_name
8
-
9
- validates :transaction_id, presence: true
10
- validates :table_name, presence: true
11
- validates :action_timestamp, presence: true
12
- validates :action, presence: true, inclusion: {in: %w[INSERT UPDATE DELETE]}
13
- validates :whodunnit, presence: true
14
- validates :old_data, presence: true, unless: ->(version) { version.new_data.present? }
15
- validates :new_data, presence: true, unless: ->(version) { version.old_data.present? }
16
8
  end
17
9
  end
18
10
  end
@@ -5,7 +5,6 @@ require 'saseo/persistence/persistor'
5
5
  module Saseo
6
6
  module Persistence
7
7
  class Consumer < Philotic::Consumer
8
- # subscribe_to philotic_message_type: :'saseo.record_audit'
9
8
  subscribe_to Saseo.config.consumer_philotic_subscription
10
9
 
11
10
  manually_acknowledge
@@ -13,7 +12,7 @@ module Saseo
13
12
  def consume(message)
14
13
  begin
15
14
  logger.debug { "received source version: #{message.id}" }
16
- Saseo::Persistence::Persistor.persist! message
15
+ Saseo::Persistence::Persistor.process message
17
16
 
18
17
  acknowledge message
19
18
  rescue => e
@@ -0,0 +1,54 @@
1
+ require 'oj'
2
+ require 'saseo/models/version'
3
+ require 'active_support/core_ext/hash/deep_merge'
4
+
5
+ module Saseo
6
+ module Persistence
7
+ module MessageFilter
8
+ extend self
9
+
10
+ WILD_CARD = '*'
11
+
12
+ def filter_message!(message)
13
+ return message unless ignored_fields_config && filter_match?(ignored_fields_config.keys, message.table_name)
14
+
15
+ table_config(message.table_name).each_pair do |fields, ignored_actions|
16
+ if filter_match?(ignored_actions, message.action)
17
+ fields_to_remove(fields, message).each do |field|
18
+ remove_field!(field, message)
19
+ end
20
+ end
21
+ end
22
+
23
+ return nil if message.old_data.blank? && message.new_data.blank?
24
+ message
25
+ end
26
+
27
+ def remove_field!(field, message)
28
+ message.old_data && message.old_data.delete(field)
29
+ message.new_data && message.new_data.delete(field)
30
+ end
31
+
32
+ def fields_to_remove(fields, message)
33
+ fields = Array(fields).map { |f| f.to_s.downcase }
34
+ fields = message.old_data.keys | message.new_data.keys if fields.include?(WILD_CARD)
35
+ fields
36
+ end
37
+
38
+ def ignored_fields_config
39
+ unless defined?(@ignored_fields_config)
40
+ @ignored_fields_config = Saseo.config.ignore_fields_config_path ? YAML::load(File.open(File.expand_path Saseo.config.ignore_fields_config_path))[Saseo.config.env] : nil
41
+ end
42
+ @ignored_fields_config
43
+ end
44
+
45
+ def filter_match?(filters, value)
46
+ (Array(filters).map { |f| f.to_s.downcase } & [WILD_CARD, value.to_s.downcase]).any?
47
+ end
48
+
49
+ def table_config(table_name)
50
+ (ignored_fields_config && ignored_fields_config[WILD_CARD] || {}).deep_merge(ignored_fields_config && ignored_fields_config[table_name] || {})
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,6 @@
1
1
  require 'oj'
2
2
  require 'saseo/models/version'
3
+ require 'saseo/persistence/message_filter'
3
4
 
4
5
  module Saseo
5
6
  module Persistence
@@ -25,30 +26,47 @@ module Saseo
25
26
  @logger ||= Logger.new(STDOUT)
26
27
  end
27
28
 
28
- def persist!(message)
29
+ def process(message)
29
30
  logger.debug { "received source version for persistence: #{message.id}" }
30
- version = Saseo::Models::Version.new
31
31
 
32
- version_attributes.each do |attr|
33
- version.send("#{attr}=", message.send(attr))
32
+ message = Saseo::Persistence::MessageFilter.filter_message!(message)
33
+ persist_message!(message) if message
34
+ end
35
+
36
+ def persist_message!(message)
37
+ save_version!(build_version(message))
38
+ end
39
+
40
+ def build_version(message)
41
+ Saseo::Models::Version.new.tap do |version|
42
+
43
+ version_attributes.each do |attr|
44
+ version.send("#{attr}=", message.send(attr))
45
+ end
46
+
47
+ # ActiveRecord 3 doesn't handle jsonb columns properly
48
+ version.old_data = message.old_data && Oj.dump(message.old_data)
49
+ version.new_data = message.new_data && Oj.dump(message.new_data)
34
50
  end
51
+ end
52
+
53
+ def save_version!(version)
54
+ if version.has_changes?
55
+ begin
56
+ version.save!
57
+ logger.debug { "saved version: #{version.id}" }
35
58
 
36
- # ActiveRecord 3 doesn't handle jsonb columns properly
37
- version.old_data = message.old_data && Oj.dump(message.old_data)
38
- version.new_data = message.new_data && Oj.dump(message.new_data)
39
-
40
- begin
41
- version.save!
42
- logger.debug { "saved version: #{message.id}" }
43
- rescue ActiveRecord::RecordNotUnique => e
44
- Philotic::Message.publish({philotic_message_type: :'saseo.error.duplicate_record'}, version.attributes)
45
- rescue ActiveRecord::StatementInvalid => e
46
- if e.message.match /PG::ConnectionBad/
47
- logger.warn { 'Lost connection to DB, attempting to reconnect.' }
48
- ActiveRecord::Base.clear_all_connections!
49
- ActiveRecord::Base.establish_connection
50
- retry
59
+ rescue ActiveRecord::RecordNotUnique => e
60
+ logger.warn "Duplicate version: #{version.attributes}"
61
+ rescue ActiveRecord::StatementInvalid => e
62
+ if e.message.match /PG::ConnectionBad/
63
+ logger.warn { 'Lost connection to DB, attempting to reconnect.' }
64
+ Saseo::Models::Version.reconnect!
65
+ retry
66
+ end
51
67
  end
68
+ else
69
+ logger.info { "Skipped version with no changes: #{version.attributes}" }
52
70
  end
53
71
  end
54
72
  end
@@ -1,3 +1,3 @@
1
1
  module Saseo
2
- VERSION = "0.4.3"
2
+ VERSION = "0.5.0"
3
3
  end
Binary file
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency 'generator_spec'
26
26
  spec.add_development_dependency 'rake', '~> 10.0'
27
27
  spec.add_development_dependency 'rspec'
28
+ spec.add_development_dependency 'shoulda-matchers', '~> 2.5'
29
+ spec.add_development_dependency 'simplecov', '= 0.10'
28
30
 
29
31
  spec.add_dependency 'oj'
30
32
  spec.add_dependency 'pg'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saseo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Keyes
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-11-17 00:00:00.000000000 Z
11
+ date: 2015-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print
@@ -108,6 +108,34 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: shoulda-matchers
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.5'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.5'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '='
130
+ - !ruby/object:Gem::Version
131
+ version: '0.10'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '='
137
+ - !ruby/object:Gem::Version
138
+ version: '0.10'
111
139
  - !ruby/object:Gem::Dependency
112
140
  name: oj
113
141
  requirement: !ruby/object:Gem::Requirement
@@ -227,12 +255,14 @@ files:
227
255
  - lib/saseo/models/version.rb
228
256
  - lib/saseo/persistence.rb
229
257
  - lib/saseo/persistence/consumer.rb
258
+ - lib/saseo/persistence/message_filter.rb
230
259
  - lib/saseo/persistence/persistor.rb
231
260
  - lib/saseo/publishing.rb
232
261
  - lib/saseo/publishing/data_change_message.rb
233
262
  - lib/saseo/publishing/publisher.rb
234
263
  - lib/saseo/version.rb
235
264
  - lib/saseo/whodunnit.rb
265
+ - sample_saseo_setup.png
236
266
  - saseo.example.yml
237
267
  - saseo.gemspec
238
268
  - tasks/bump.rake