deckard 0.2.0 → 0.3.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 +16 -1
- data/README.md +11 -3
- data/lib/deckard/model_config.rb +14 -6
- data/lib/deckard/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a0545ee7c006b54aaedd28b162ee6eb06647b0812bfbbdcb3b5846a78d6cdd68
|
|
4
|
+
data.tar.gz: 9cf0a020aaeabaf9d659549b3045fe9ba2b4a758ee40106163a6aead95c7a778
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 33e82c2fbba3856af1019a61bc1cf181e6f74383824895ab667d76aedd1994a04af5e69534c73f379ba2b64f333748319767290511f97eaefb13fbb75e674b83
|
|
7
|
+
data.tar.gz: dacd253d2915316b2549f6ea4196354055f0abd4b504b14c9e6980ecab11f83d676a1868e81751c785ee813fd242bd256361daaae475c5078eda6c227364d0aa
|
data/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,22 @@ All notable changes to deckard are recorded here. The format follows
|
|
|
5
5
|
[Semantic Versioning](https://semver.org/). Before 1.0, minor versions may
|
|
6
6
|
change the stream format and the Ruby API.
|
|
7
7
|
|
|
8
|
-
## [0.
|
|
8
|
+
## [0.3.0] - Unreleased
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `natural_keys` inside a `replicate` block: one table of class name to
|
|
13
|
+
attribute name or names, the short form for a reached class that only
|
|
14
|
+
needs a natural key. `model "Name" do natural_key ... end` still works
|
|
15
|
+
for an entry that also names associations or omissions.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- A plan gives each class one natural key. Declaring it twice in the same
|
|
20
|
+
plan is reported by validation as a `ConfigurationError`; before, the
|
|
21
|
+
later declaration silently replaced the earlier one.
|
|
22
|
+
|
|
23
|
+
## [0.2.0] - 2026-09-30
|
|
9
24
|
|
|
10
25
|
### Changed
|
|
11
26
|
|
data/README.md
CHANGED
|
@@ -92,7 +92,7 @@ gives every order the full plan, and a record two dumps share lands once.
|
|
|
92
92
|
|
|
93
93
|
## Plans
|
|
94
94
|
|
|
95
|
-
The `replicate` block offers
|
|
95
|
+
The `replicate` block offers six methods:
|
|
96
96
|
|
|
97
97
|
```ruby
|
|
98
98
|
replicate do
|
|
@@ -101,17 +101,25 @@ replicate do
|
|
|
101
101
|
omit_fields :internal_notes # keep a field out of the stream
|
|
102
102
|
omit_associations :warehouse # do not traverse this association
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
natural_keys "Product" => :sku, # how each reached class is matched
|
|
105
|
+
"Warehouse" => [:region, :code]
|
|
106
|
+
|
|
107
|
+
model "LineItem" do # the first four, for a class the dump reaches
|
|
105
108
|
associations :adjustments
|
|
106
109
|
end
|
|
107
110
|
end
|
|
108
111
|
```
|
|
109
112
|
|
|
113
|
+
Most reached classes need nothing but a natural key, and `natural_keys` says
|
|
114
|
+
that for all of them in one table. A `model` block is for the rest: a
|
|
115
|
+
collection to bring along, a field to leave out. A plan gives each class one
|
|
116
|
+
key, so naming it in both places is a plan problem, not an override.
|
|
117
|
+
|
|
110
118
|
Classes are named as strings, so the root never forces them to load first,
|
|
111
119
|
and an STI subclass follows the entry for its nearest declared ancestor. Each
|
|
112
120
|
record travels with the natural key its plan gave it, so the destination
|
|
113
121
|
needs no plan of its own. That also means a natural key is repeated in every
|
|
114
|
-
plan whose dumps reach the class: a Customer
|
|
122
|
+
plan whose dumps reach the class: a Customer line in Order's plan and one in
|
|
115
123
|
Invoice's, each saying how a customer is matched.
|
|
116
124
|
|
|
117
125
|
Before dumping, the `deckard` executable eager loads the application so
|
data/lib/deckard/model_config.rb
CHANGED
|
@@ -4,10 +4,10 @@ require "active_support/core_ext/string/inflections"
|
|
|
4
4
|
|
|
5
5
|
module Deckard
|
|
6
6
|
# A replication plan: a root model's `replicate do ... end` block. The plan
|
|
7
|
-
# is an entry for the root plus
|
|
8
|
-
#
|
|
9
|
-
# finds its entry through its ancestors, so an
|
|
10
|
-
# nearest declared ancestor. See docs/traversal.md.
|
|
7
|
+
# is an entry for the root plus an entry for each class its dumps reach,
|
|
8
|
+
# declared through `natural_keys` or `model`, all in one table shared by
|
|
9
|
+
# the plan's entries. A class finds its entry through its ancestors, so an
|
|
10
|
+
# STI subclass follows its nearest declared ancestor. See docs/traversal.md.
|
|
11
11
|
class ModelConfig
|
|
12
12
|
attr_reader :name, :extra_associations, :natural_key_attributes, :omitted_fields, :omitted_associations
|
|
13
13
|
|
|
@@ -47,11 +47,17 @@ module Deckard
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
# DSL: attributes identifying an existing destination record to reuse.
|
|
50
|
-
#
|
|
50
|
+
# Declaring it twice in one plan is a problem, not an override.
|
|
51
51
|
def natural_key(*attributes)
|
|
52
|
+
@redeclared_natural_key = !@natural_key_attributes.empty?
|
|
52
53
|
@natural_key_attributes = attributes.map(&:to_s)
|
|
53
54
|
end
|
|
54
55
|
|
|
56
|
+
# DSL: class name to natural key, for reached classes needing nothing else.
|
|
57
|
+
def natural_keys(keys)
|
|
58
|
+
keys.each { |name, attributes| model(name) { natural_key(*attributes) } }
|
|
59
|
+
end
|
|
60
|
+
|
|
55
61
|
# DSL: fields to exclude from dumped attributes. Additive across calls.
|
|
56
62
|
def omit_fields(*names)
|
|
57
63
|
@omitted_fields |= names.map(&:to_s)
|
|
@@ -104,9 +110,11 @@ module Deckard
|
|
|
104
110
|
missing = attributes - model.attribute_names
|
|
105
111
|
problems += missing.map { |attribute| "#{model} has no #{attribute.inspect} attribute" }
|
|
106
112
|
end
|
|
107
|
-
problems
|
|
113
|
+
problems += (@natural_key_attributes & @omitted_fields).map do |attribute|
|
|
108
114
|
"#{model} names #{attribute.inspect} as both a natural key attribute and an omitted field"
|
|
109
115
|
end
|
|
116
|
+
problems << "#{model} is given a natural key more than once in the same plan" if @redeclared_natural_key
|
|
117
|
+
problems
|
|
110
118
|
end
|
|
111
119
|
|
|
112
120
|
# The plan as data, root entry first: what PlanReport renders.
|
data/lib/deckard/version.rb
CHANGED