clone_kit 0.3.1 → 0.4.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/.gitignore +2 -0
- data/.rubocop.kapost.yml +5 -0
- data/bin/console +1 -0
- data/clone_kit.gemspec +13 -8
- data/lib/clone_kit.rb +6 -0
- data/lib/clone_kit/active_record_specification.rb +18 -0
- data/lib/clone_kit/cloners/active_record_merging_ruleset_cloner.rb +109 -0
- data/lib/clone_kit/cloners/active_record_ruleset_cloner.rb +110 -0
- data/lib/clone_kit/cloners/mongoid_merging_ruleset_cloner.rb +1 -1
- data/lib/clone_kit/cloners/mongoid_ruleset_cloner.rb +11 -4
- data/lib/clone_kit/cloners/no_op.rb +2 -0
- data/lib/clone_kit/graph.rb +1 -1
- data/lib/clone_kit/id_generators/bson.rb +17 -0
- data/lib/clone_kit/id_generators/invalid_id.rb +8 -0
- data/lib/clone_kit/id_generators/uuid.rb +15 -0
- data/lib/clone_kit/merge_attributes_tool.rb +1 -1
- data/lib/clone_kit/mongo_specification.rb +23 -0
- data/lib/clone_kit/rule.rb +6 -0
- data/lib/clone_kit/rules/remap.rb +5 -4
- data/lib/clone_kit/rules/safe_remap.rb +4 -3
- data/lib/clone_kit/shared_id_map.rb +6 -5
- data/lib/clone_kit/specification.rb +7 -14
- data/lib/clone_kit/version.rb +1 -1
- metadata +97 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12c6dfb57705d29b62b6902c77408277f3757268
|
4
|
+
data.tar.gz: e8ddf096944716d6c980fb69f768f3b79e927c7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a6b30be94b2de7d397fc724abd2107cdc59cd4f8f7d337d6bbcb9d3b58c8f0e2ea9da2878b53dbe7e16d61255844469625f5c51d99a4d2960d6ec0336f2d7d5
|
7
|
+
data.tar.gz: cba1dced859dc1d9dd89751d99e7e4242beba9059a2ea4e7ecc35de343ffd88e4d8a5f1e53cf1bb5c0bac3df7ca348fa0aa857fecf841956faa7edb73eba7346
|
data/.gitignore
CHANGED
data/.rubocop.kapost.yml
CHANGED
@@ -28,6 +28,8 @@ AllCops:
|
|
28
28
|
TargetRubyVersion: 2.3
|
29
29
|
Style/AndOr:
|
30
30
|
EnforcedStyle: conditionals
|
31
|
+
Style/BracesAroundHashParameters:
|
32
|
+
EnforcedStyle: context_dependent
|
31
33
|
Style/CaseIndentation:
|
32
34
|
IndentOneStep: true
|
33
35
|
Style/Documentation:
|
@@ -97,3 +99,6 @@ Lint/PercentStringArray:
|
|
97
99
|
Exclude:
|
98
100
|
# SecureHeaders needs the single quotes in `%w[https: 'self']`
|
99
101
|
- config/initializers/secure_headers.rb
|
102
|
+
Style/SignalException:
|
103
|
+
Description: 'Checks for proper usage of fail and raise.' # the proper usage is 'raise'
|
104
|
+
Enabled: false
|
data/bin/console
CHANGED
data/clone_kit.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
lib = File.expand_path("
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require "clone_kit/version"
|
6
6
|
|
@@ -22,16 +22,21 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = spec.files.grep(%r(^exe/)) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
|
-
spec.add_runtime_dependency "redis"
|
26
25
|
spec.add_runtime_dependency "activesupport", "> 3.0.0" # For core ext Array#wrap and Object#blank?
|
26
|
+
spec.add_runtime_dependency "redis"
|
27
27
|
|
28
|
+
spec.add_development_dependency "activerecord", "~> 4.0"
|
28
29
|
spec.add_development_dependency "bundler", "~> 1.13"
|
29
|
-
spec.add_development_dependency "
|
30
|
+
spec.add_development_dependency "combustion", "~> 0.7.0"
|
30
31
|
spec.add_development_dependency "database_cleaner", "1.5.3"
|
32
|
+
spec.add_development_dependency "fakeredis"
|
33
|
+
spec.add_development_dependency "mongoid", "~> 4.0.2"
|
34
|
+
spec.add_development_dependency "pg", "~> 0.18.4"
|
35
|
+
spec.add_development_dependency "pry"
|
36
|
+
spec.add_development_dependency "pry-byebug"
|
31
37
|
spec.add_development_dependency "rake", "~> 11.0"
|
32
|
-
spec.add_development_dependency "rspec", "~> 3.4"
|
33
38
|
spec.add_development_dependency "rspec-collection_matchers"
|
34
|
-
spec.add_development_dependency "
|
35
|
-
spec.add_development_dependency "
|
36
|
-
spec.add_development_dependency "
|
39
|
+
spec.add_development_dependency "rspec-rails", "~> 3.4"
|
40
|
+
spec.add_development_dependency "rubocop"
|
41
|
+
spec.add_development_dependency "simplecov", "~> 0.12.0"
|
37
42
|
end
|
data/lib/clone_kit.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require "clone_kit/version"
|
4
4
|
require "clone_kit/graph"
|
5
5
|
require "clone_kit/specification"
|
6
|
+
require "clone_kit/mongo_specification"
|
7
|
+
require "clone_kit/active_record_specification"
|
6
8
|
require "clone_kit/operation"
|
7
9
|
require "clone_kit/shared_id_map"
|
8
10
|
require "clone_kit/rule"
|
@@ -24,6 +26,10 @@ module CloneKit
|
|
24
26
|
@spec ||= {}
|
25
27
|
end
|
26
28
|
|
29
|
+
def self.reset_graph!
|
30
|
+
@graph = nil
|
31
|
+
end
|
32
|
+
|
27
33
|
def self.add_specification(specification)
|
28
34
|
spec[specification.model.name] = specification
|
29
35
|
refresh_specification(specification)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "clone_kit/specification"
|
4
|
+
require "clone_kit/id_generators/uuid"
|
5
|
+
|
6
|
+
module CloneKit
|
7
|
+
class ActiveRecordSpecification < Specification
|
8
|
+
protected
|
9
|
+
|
10
|
+
def validate!
|
11
|
+
fail SpecificationError, "Model type not supported" unless active_record_document?
|
12
|
+
end
|
13
|
+
|
14
|
+
def active_record_document?
|
15
|
+
defined?(ActiveRecord) && model < ActiveRecord::Base
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "clone_kit/cloners/active_record_ruleset_cloner"
|
4
|
+
|
5
|
+
module CloneKit
|
6
|
+
module Cloners
|
7
|
+
class ActiveRecordMergingRulesetCloner < ActiveRecordRulesetCloner
|
8
|
+
ID = "id"
|
9
|
+
|
10
|
+
def initialize(model_klass, rules: [], merge_fields: ["name"])
|
11
|
+
super(model_klass, rules: rules)
|
12
|
+
self.merge_fields = merge_fields
|
13
|
+
end
|
14
|
+
|
15
|
+
def clone_ids(ids, operation)
|
16
|
+
@saved_id_map = {}
|
17
|
+
initialize_cloner(operation)
|
18
|
+
apply_rules_and_save(find_and_merge_existing_records(ids))
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
# These methods are super simple and should usually be overridden to merge records in a more nuanced fashion
|
24
|
+
|
25
|
+
def compare(first, second)
|
26
|
+
merge_fields.all? { |name| first[name] == second[name] }
|
27
|
+
end
|
28
|
+
|
29
|
+
def merge(records)
|
30
|
+
result = nil
|
31
|
+
records.each do |rec|
|
32
|
+
result = if result.nil?
|
33
|
+
rec.deep_dup
|
34
|
+
else
|
35
|
+
result.merge(rec)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_accessor :merge_fields
|
45
|
+
|
46
|
+
def find_and_merge_existing_records(ids, mergeable: Set.new, skip: skip = Set.new)
|
47
|
+
all_records = []
|
48
|
+
each_existing_record(ids) do |rec|
|
49
|
+
all_records << rec
|
50
|
+
end
|
51
|
+
|
52
|
+
result = []
|
53
|
+
|
54
|
+
all_records.each_with_index do |record, i|
|
55
|
+
next if skip.include?(record[ID])
|
56
|
+
mergeable << record
|
57
|
+
|
58
|
+
all_records[i + 1..all_records.length].each do |other_record|
|
59
|
+
next unless compare(record, other_record)
|
60
|
+
|
61
|
+
mergeable << other_record
|
62
|
+
skip << other_record[ID]
|
63
|
+
end
|
64
|
+
|
65
|
+
new_id = generate_new_id
|
66
|
+
new_record = if mergeable.length == 1
|
67
|
+
copy = clone(mergeable.first)
|
68
|
+
@saved_id_map[copy[ID]] = new_id
|
69
|
+
copy
|
70
|
+
else
|
71
|
+
merged = merge(mergeable)
|
72
|
+
|
73
|
+
mergeable.each do |m|
|
74
|
+
@saved_id_map[m[ID]] ||= new_id
|
75
|
+
end
|
76
|
+
merged
|
77
|
+
end
|
78
|
+
|
79
|
+
new_record[ID] = new_id
|
80
|
+
|
81
|
+
result << new_record
|
82
|
+
end
|
83
|
+
|
84
|
+
CloneKit::SharedIdMap
|
85
|
+
.new(current_operation.id)
|
86
|
+
.insert_many(model_klass, @saved_id_map)
|
87
|
+
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
def apply_rules_and_save(records)
|
92
|
+
records.each do |attributes|
|
93
|
+
id = attributes[ID]
|
94
|
+
rules.each do |rule|
|
95
|
+
begin
|
96
|
+
rule.fix(@saved_id_map.key(id), attributes)
|
97
|
+
rescue StandardError => e
|
98
|
+
id = attributes[ID]
|
99
|
+
message = "Unhandled error when applying rule #{rule.class.name} to #{model_klass} #{id}: #{e.class}"
|
100
|
+
current_operation.error(message)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
save_or_fail(attributes)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "clone_kit/decorators/embedded_cloner_decorator"
|
4
|
+
|
5
|
+
module CloneKit
|
6
|
+
module Cloners
|
7
|
+
class ActiveRecordRulesetCloner
|
8
|
+
attr_accessor :rules, :id_generator
|
9
|
+
|
10
|
+
def initialize(model_klass, rules: [], id_generator: IdGenerators::Uuid)
|
11
|
+
self.model_klass = model_klass
|
12
|
+
self.rules = rules
|
13
|
+
self.id_generator = id_generator
|
14
|
+
end
|
15
|
+
|
16
|
+
def clone_ids(ids, operation)
|
17
|
+
initialize_cloner(operation)
|
18
|
+
|
19
|
+
map = {}
|
20
|
+
result = []
|
21
|
+
|
22
|
+
each_existing_record(ids) do |attributes|
|
23
|
+
attributes = clone(attributes)
|
24
|
+
result << apply_rules_and_save(map, attributes)
|
25
|
+
end
|
26
|
+
|
27
|
+
CloneKit::SharedIdMap.new(operation.id).insert_many(model_klass, map)
|
28
|
+
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
attr_accessor :model_klass,
|
35
|
+
:current_operation
|
36
|
+
|
37
|
+
def clone(attributes)
|
38
|
+
attributes.deep_dup
|
39
|
+
end
|
40
|
+
|
41
|
+
def apply_rules_and_save(mapping, attributes)
|
42
|
+
new_id = generate_new_id
|
43
|
+
old_id = attributes["id"]
|
44
|
+
mapping[old_id] = new_id
|
45
|
+
attributes["id"] = new_id
|
46
|
+
|
47
|
+
rules.each do |rule|
|
48
|
+
rule.id_generator = id_generator
|
49
|
+
|
50
|
+
begin
|
51
|
+
rule.fix(old_id, attributes)
|
52
|
+
rescue StandardError => e
|
53
|
+
message = "Unhandled error when applying rule #{rule.class.name} to #{model_klass} #{new_id}: #{e.class}"
|
54
|
+
current_operation.error(message)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
save_or_fail(attributes)
|
59
|
+
attributes
|
60
|
+
end
|
61
|
+
|
62
|
+
def generate_new_id
|
63
|
+
id_generator.next
|
64
|
+
end
|
65
|
+
|
66
|
+
def save_or_fail(attributes)
|
67
|
+
document_klass = model_klass
|
68
|
+
model_that_we_wont_save = document_klass.new(attributes)
|
69
|
+
if model_that_we_wont_save.valid?
|
70
|
+
insert(model_that_we_wont_save)
|
71
|
+
else
|
72
|
+
details = model_that_we_wont_save.errors.full_messages.to_sentence
|
73
|
+
id = attributes["id"]
|
74
|
+
current_operation.error("#{model_klass} #{id} failed model validation and was not cloned: #{details}")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def insert(model)
|
79
|
+
insert_op = model.class.arel_table.create_insert.tap do |insert_mgr|
|
80
|
+
insert_mgr.insert(
|
81
|
+
model.send(:arel_attributes_with_values_for_create, model.attribute_names)
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
connection.execute(insert_op.to_sql)
|
86
|
+
end
|
87
|
+
|
88
|
+
def each_existing_record(ids)
|
89
|
+
ids.each do |id|
|
90
|
+
record = model_klass.find_by(model_klass.primary_key => id).attributes
|
91
|
+
next if record.nil?
|
92
|
+
|
93
|
+
yield record
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def initialize_cloner(operation)
|
98
|
+
@current_operation = operation
|
99
|
+
|
100
|
+
rules.each do |rule|
|
101
|
+
rule.current_operation = @current_operation
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def connection
|
106
|
+
ActiveRecord::Base.connection
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -6,13 +6,14 @@ require "clone_kit/decorators/embedded_cloner_decorator"
|
|
6
6
|
module CloneKit
|
7
7
|
module Cloners
|
8
8
|
class MongoidRulesetCloner
|
9
|
-
attr_accessor :rules
|
9
|
+
attr_accessor :rules, :id_generator
|
10
10
|
|
11
|
-
def initialize(model_klass, rules: [])
|
11
|
+
def initialize(model_klass, rules: [], id_generator: CloneKit::IdGenerators::Bson)
|
12
12
|
self.model_klass = model_klass
|
13
13
|
self.rules = [
|
14
14
|
CloneKit::Rules::AllowOnlyMongoidFields.new(model_klass)
|
15
15
|
] + rules
|
16
|
+
self.id_generator = id_generator
|
16
17
|
end
|
17
18
|
|
18
19
|
def clone_ids(ids, operation)
|
@@ -58,7 +59,7 @@ module CloneKit
|
|
58
59
|
|
59
60
|
return empty_embedded(metadata) if first_item.nil?
|
60
61
|
|
61
|
-
cloner = MongoidRulesetCloner.new(polymorphic_class(metadata.class_name, first_item))
|
62
|
+
cloner = MongoidRulesetCloner.new(polymorphic_class(metadata.class_name, first_item), id_generator: id_generator)
|
62
63
|
embedded_cloner = CloneKit::Decorators::EmbeddedClonerDecorator.new(cloner, records: Array.wrap(item))
|
63
64
|
|
64
65
|
embedded_attributes = embedded_cloner.clone_embedded(current_operation)
|
@@ -75,12 +76,14 @@ module CloneKit
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def apply_rules_and_save(mapping, attributes)
|
78
|
-
new_id =
|
79
|
+
new_id = generate_new_id
|
79
80
|
old_id = attributes["_id"]
|
80
81
|
mapping[attributes["_id"]] = new_id
|
81
82
|
attributes["_id"] = new_id
|
82
83
|
|
83
84
|
rules.each do |rule|
|
85
|
+
rule.id_generator = id_generator
|
86
|
+
|
84
87
|
begin
|
85
88
|
rule.fix(old_id, attributes)
|
86
89
|
rescue StandardError => e
|
@@ -93,6 +96,10 @@ module CloneKit
|
|
93
96
|
attributes
|
94
97
|
end
|
95
98
|
|
99
|
+
def generate_new_id
|
100
|
+
id_generator.next
|
101
|
+
end
|
102
|
+
|
96
103
|
def save_or_fail(attributes)
|
97
104
|
document_klass = model_klass
|
98
105
|
document_klass = attributes["_type"].constantize if attributes.key?("_type")
|
data/lib/clone_kit/graph.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CloneKit
|
4
|
+
module IdGenerators
|
5
|
+
module Bson
|
6
|
+
def self.next
|
7
|
+
BSON::ObjectId.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.from_string(val)
|
11
|
+
BSON::ObjectId.from_string(val)
|
12
|
+
rescue BSON::ObjectId::Invalid => error
|
13
|
+
raise InvalidId, error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "clone_kit/specification"
|
4
|
+
require "clone_kit/id_generators/bson"
|
5
|
+
|
6
|
+
module CloneKit
|
7
|
+
class MongoSpecification < Specification
|
8
|
+
protected
|
9
|
+
|
10
|
+
def validate!
|
11
|
+
fail SpecificationError, "Model type not supported" unless mongoid_document?
|
12
|
+
fail SpecificationError, "Cannot clone embedded documents" if mongoid_embedded_document?
|
13
|
+
end
|
14
|
+
|
15
|
+
def mongoid_document?
|
16
|
+
defined?(Mongoid) && model < Mongoid::Document
|
17
|
+
end
|
18
|
+
|
19
|
+
def mongoid_embedded_document?
|
20
|
+
mongoid_document? && model.embedded?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/clone_kit/rule.rb
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
module CloneKit
|
4
4
|
module Rules
|
5
5
|
class Remap < CloneKit::Rule
|
6
|
-
def initialize(model_name, remap_hash = {})
|
6
|
+
def initialize(model_name, remap_hash = {}, id_generator: nil)
|
7
|
+
super(id_generator: id_generator)
|
7
8
|
self.remap_hash = remap_hash
|
8
9
|
self.model_name = model_name
|
9
10
|
end
|
@@ -14,7 +15,7 @@ module CloneKit
|
|
14
15
|
next unless try?(attributes, att)
|
15
16
|
|
16
17
|
attributes[att] = if attributes[att].is_a?(Array)
|
17
|
-
attributes[att].map { |id| remap(klass, id)
|
18
|
+
attributes[att].map { |id| remap(klass, id) if id.present? }.compact
|
18
19
|
else
|
19
20
|
remap(klass, attributes[att])
|
20
21
|
end
|
@@ -25,14 +26,14 @@ module CloneKit
|
|
25
26
|
protected
|
26
27
|
|
27
28
|
def remap(klass, old_id)
|
28
|
-
shared_id_map.lookup(klass, old_id)
|
29
|
+
shared_id_map.lookup(klass, old_id, id_generator: id_generator)
|
29
30
|
rescue ArgumentError
|
30
31
|
error_event("#{model_name} missing remapped id for #{klass} #{old_id}")
|
31
32
|
nil
|
32
33
|
end
|
33
34
|
|
34
35
|
def try?(attributes, key)
|
35
|
-
attributes.key?(key) &&
|
36
|
+
attributes.key?(key) && attributes[key].present?
|
36
37
|
end
|
37
38
|
|
38
39
|
private
|
@@ -5,15 +5,16 @@ require "clone_kit/rules/remap"
|
|
5
5
|
module CloneKit
|
6
6
|
module Rules
|
7
7
|
class SafeRemap < Remap
|
8
|
-
def initialize(model_name, remap_hash = {}, safe_value = nil)
|
8
|
+
def initialize(model_name, remap_hash = {}, safe_value = nil, id_generator: nil)
|
9
|
+
super(model_name, remap_hash, id_generator: id_generator)
|
9
10
|
self.safe_value = safe_value
|
10
|
-
super(model_name, remap_hash)
|
11
11
|
end
|
12
12
|
|
13
13
|
protected
|
14
14
|
|
15
15
|
def remap(klass, old_id)
|
16
|
-
result = shared_id_map
|
16
|
+
result = shared_id_map
|
17
|
+
.lookup_safe(klass, old_id, safe_value, id_generator: id_generator)
|
17
18
|
warn_event("#{model_name} missing remapped id for #{klass}/#{old_id}") if result == safe_value
|
18
19
|
result
|
19
20
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "redis"
|
4
|
+
require "clone_kit/id_generators/invalid_id"
|
4
5
|
|
5
6
|
module CloneKit
|
6
7
|
class SharedIdMap
|
@@ -11,18 +12,18 @@ module CloneKit
|
|
11
12
|
self.redis = redis
|
12
13
|
end
|
13
14
|
|
14
|
-
def lookup(klass, original_id)
|
15
|
-
|
16
|
-
rescue
|
15
|
+
def lookup(klass, original_id, id_generator: IdGenerators::Bson)
|
16
|
+
id_generator.from_string(redis.hget(hash_key(klass), original_id.to_s))
|
17
|
+
rescue IdGenerators::InvalidId
|
17
18
|
raise ArgumentError, "No mapping found for #{klass}. This usually indicates a dependency has not be specified"
|
18
19
|
end
|
19
20
|
|
20
|
-
def lookup_safe(klass, original_id, default = nil)
|
21
|
+
def lookup_safe(klass, original_id, default = nil, id_generator: IdGenerators::Bson)
|
21
22
|
val = redis.hget(hash_key(klass), original_id.to_s)
|
22
23
|
if val.blank?
|
23
24
|
default
|
24
25
|
else
|
25
|
-
|
26
|
+
id_generator.from_string(val)
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "clone_kit/emitters/empty"
|
4
4
|
require "clone_kit/cloners/no_op"
|
5
|
+
require "clone_kit/id_generators/uuid"
|
5
6
|
|
6
7
|
module CloneKit
|
7
8
|
class SpecificationError < StandardError; end
|
@@ -21,12 +22,13 @@ module CloneKit
|
|
21
22
|
self.emitter = EMPTY_EMITTER
|
22
23
|
self.cloner = NO_OP_CLONER
|
23
24
|
self.dependencies = []
|
24
|
-
self.after_operation_block = ->
|
25
|
+
self.after_operation_block = ->(_op) {}
|
26
|
+
|
27
|
+
configure
|
25
28
|
|
26
29
|
validate!
|
27
30
|
|
28
31
|
model.instance_exec(self, &block)
|
29
|
-
|
30
32
|
CloneKit.add_specification(self)
|
31
33
|
end
|
32
34
|
|
@@ -34,19 +36,10 @@ module CloneKit
|
|
34
36
|
self.after_operation_block = block
|
35
37
|
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
def validate!
|
40
|
-
fail SpecificationError, "Model type not supported" unless mongoid_document?
|
41
|
-
fail SpecificationError, "Cannot clone embedded documents" if mongoid_embedded_document?
|
42
|
-
end
|
39
|
+
protected
|
43
40
|
|
44
|
-
def
|
45
|
-
defined?(Mongoid) && model < Mongoid::Document
|
46
|
-
end
|
41
|
+
def configure; end
|
47
42
|
|
48
|
-
def
|
49
|
-
mongoid_document? && model.embedded?
|
50
|
-
end
|
43
|
+
def validate!; end
|
51
44
|
end
|
52
45
|
end
|
data/lib/clone_kit/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clone_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Croft
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.0.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: redis
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -25,19 +39,19 @@ dependencies:
|
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
42
|
+
name: activerecord
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
|
-
- - "
|
45
|
+
- - "~>"
|
32
46
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
type: :
|
47
|
+
version: '4.0'
|
48
|
+
type: :development
|
35
49
|
prerelease: false
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
|
-
- - "
|
52
|
+
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
54
|
+
version: '4.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,19 +67,19 @@ dependencies:
|
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '1.13'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
70
|
+
name: combustion
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
75
|
+
version: 0.7.0
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
82
|
+
version: 0.7.0
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: database_cleaner
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,35 +95,49 @@ dependencies:
|
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: 1.5.3
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
98
|
+
name: fakeredis
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: mongoid
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
86
114
|
requirements:
|
87
115
|
- - "~>"
|
88
116
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
117
|
+
version: 4.0.2
|
90
118
|
type: :development
|
91
119
|
prerelease: false
|
92
120
|
version_requirements: !ruby/object:Gem::Requirement
|
93
121
|
requirements:
|
94
122
|
- - "~>"
|
95
123
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
124
|
+
version: 4.0.2
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
126
|
+
name: pg
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
100
128
|
requirements:
|
101
129
|
- - "~>"
|
102
130
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
131
|
+
version: 0.18.4
|
104
132
|
type: :development
|
105
133
|
prerelease: false
|
106
134
|
version_requirements: !ruby/object:Gem::Requirement
|
107
135
|
requirements:
|
108
136
|
- - "~>"
|
109
137
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
138
|
+
version: 0.18.4
|
111
139
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
140
|
+
name: pry
|
113
141
|
requirement: !ruby/object:Gem::Requirement
|
114
142
|
requirements:
|
115
143
|
- - ">="
|
@@ -137,7 +165,21 @@ dependencies:
|
|
137
165
|
- !ruby/object:Gem::Version
|
138
166
|
version: '0'
|
139
167
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
168
|
+
name: rake
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '11.0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '11.0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rspec-collection_matchers
|
141
183
|
requirement: !ruby/object:Gem::Requirement
|
142
184
|
requirements:
|
143
185
|
- - ">="
|
@@ -151,7 +193,21 @@ dependencies:
|
|
151
193
|
- !ruby/object:Gem::Version
|
152
194
|
version: '0'
|
153
195
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
196
|
+
name: rspec-rails
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '3.4'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '3.4'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: rubocop
|
155
211
|
requirement: !ruby/object:Gem::Requirement
|
156
212
|
requirements:
|
157
213
|
- - ">="
|
@@ -164,6 +220,20 @@ dependencies:
|
|
164
220
|
- - ">="
|
165
221
|
- !ruby/object:Gem::Version
|
166
222
|
version: '0'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: simplecov
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - "~>"
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: 0.12.0
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - "~>"
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: 0.12.0
|
167
237
|
description: Supports rules-based cloning, Mongoid, and distributed operations
|
168
238
|
email:
|
169
239
|
- brandon@kapost.com
|
@@ -183,6 +253,9 @@ files:
|
|
183
253
|
- bin/setup
|
184
254
|
- clone_kit.gemspec
|
185
255
|
- lib/clone_kit.rb
|
256
|
+
- lib/clone_kit/active_record_specification.rb
|
257
|
+
- lib/clone_kit/cloners/active_record_merging_ruleset_cloner.rb
|
258
|
+
- lib/clone_kit/cloners/active_record_ruleset_cloner.rb
|
186
259
|
- lib/clone_kit/cloners/mongoid_merging_ruleset_cloner.rb
|
187
260
|
- lib/clone_kit/cloners/mongoid_ruleset_cloner.rb
|
188
261
|
- lib/clone_kit/cloners/no_op.rb
|
@@ -190,7 +263,11 @@ files:
|
|
190
263
|
- lib/clone_kit/emitters/empty.rb
|
191
264
|
- lib/clone_kit/event_outlet.rb
|
192
265
|
- lib/clone_kit/graph.rb
|
266
|
+
- lib/clone_kit/id_generators/bson.rb
|
267
|
+
- lib/clone_kit/id_generators/invalid_id.rb
|
268
|
+
- lib/clone_kit/id_generators/uuid.rb
|
193
269
|
- lib/clone_kit/merge_attributes_tool.rb
|
270
|
+
- lib/clone_kit/mongo_specification.rb
|
194
271
|
- lib/clone_kit/operation.rb
|
195
272
|
- lib/clone_kit/rule.rb
|
196
273
|
- lib/clone_kit/rules/allow_only_mongoid_fields.rb
|