foobara 0.0.36 → 0.0.38
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 +6 -0
- data/README.md +36 -54
- data/projects/command/src/concerns/domain_mappers.rb +109 -19
- data/projects/common/src/error.rb +4 -1
- data/projects/domain/lib/foobara/domain.rb +0 -6
- data/projects/domain/src/domain_module_extension.rb +6 -14
- data/projects/domain_mapper/lib/foobara/domain_mapper.rb +10 -0
- data/projects/domain_mapper/src/domain_mapper.rb +106 -0
- data/projects/{domain/src/domain_mapper/registry.rb → domain_mapper/src/domain_mapper_lookups.rb} +21 -19
- data/projects/foobara/lib/foobara/all.rb +3 -3
- metadata +6 -4
- data/projects/domain/src/domain_mapper.rb +0 -166
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc8a84b48b8479025a63b5ae393436a12826aa19291bf8f60d453e891e5bc433
|
4
|
+
data.tar.gz: 6a0b086f7b5921f2301c566f53c8bc5b2d22f59693c9349adbeb727d49323cc4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70b1b7689b897bc3a7b7ef790fdf3b343901602948b4107e2606cc8e5a98a3b352d70f519759246127d293fa6e81fa250ba94b7d4341199b8aa70ebbff5b603b
|
7
|
+
data.tar.gz: 00a4a5a17cacb2aeacf6d5b03a2938f2d93c55c598b4e109d72bd57d75234e66b457e3331a17e34a342124f731bedeadbda33c7e3ac7bb5b8bf540ca51be70ed
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## [0.0.37] - 2024-12-11
|
2
|
+
|
3
|
+
- Make DomainMappers extend Command so they have possible errors and statefulness/a cleaner API
|
4
|
+
- Fixup domain mapper lookups to give proper values/errors in various scenarios, particularly in the context
|
5
|
+
of running a subcommand
|
6
|
+
|
1
7
|
## [0.0.36] - 2024-12-10
|
2
8
|
|
3
9
|
- Fix bug with command-named convenience functions
|
data/README.md
CHANGED
@@ -1386,25 +1386,29 @@ module FoobaraDemo
|
|
1386
1386
|
module CapyCafe
|
1387
1387
|
foobara_depends_on AnimalHouse
|
1388
1388
|
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1389
|
+
module DomainMappers
|
1390
|
+
class MapAnimalToCapybara < Foobara::DomainMapper
|
1391
|
+
from AnimalHouse::Animal
|
1392
|
+
to CreateCapybara
|
1393
|
+
|
1394
|
+
def map
|
1395
|
+
{
|
1396
|
+
name: "#{first_name} #{last_name}",
|
1397
|
+
age: birthday_to_age
|
1398
|
+
}
|
1399
|
+
end
|
1392
1400
|
|
1393
|
-
|
1394
|
-
age = birthday_to_age(animal.birthday)
|
1401
|
+
alias animal from
|
1395
1402
|
|
1396
|
-
|
1397
|
-
name: "#{animal.first_name} #{animal.last_name}",
|
1398
|
-
age:
|
1399
|
-
}
|
1400
|
-
end
|
1403
|
+
foobara_delegate :first_name, :last_name, :birthday, to: :animal
|
1401
1404
|
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1405
|
+
def birthday_to_age
|
1406
|
+
today = Date.today
|
1407
|
+
age = today.year - birthday.year
|
1408
|
+
birthday_this_year = Date.new(birthday.year + age, birthday.month, birthday.day)
|
1406
1409
|
|
1407
|
-
|
1410
|
+
today < birthday_this_year ? age - 1 : age
|
1411
|
+
end
|
1408
1412
|
end
|
1409
1413
|
end
|
1410
1414
|
end
|
@@ -1420,7 +1424,7 @@ of a command. But we can play with it directly:
|
|
1420
1424
|
|
1421
1425
|
```irb
|
1422
1426
|
$ ./animal_house_import.rb
|
1423
|
-
> create_capybara_inputs = FoobaraDemo::CapyCafe::
|
1427
|
+
> create_capybara_inputs = FoobaraDemo::CapyCafe::DomainMappers::MapAnimalToCapybara.map!(species: :capybara, first_name: "Barbara", last_name: "Doe", birthday: "1000-01-01")
|
1424
1428
|
==> {:name=>"Barbara Doe", :age=>1024}
|
1425
1429
|
> barbara = FoobaraDemo::CapyCafe::CreateCapybara.run!(create_capybara_inputs)
|
1426
1430
|
==> <Capybara:2>
|
@@ -1430,7 +1434,11 @@ $ ./animal_house_import.rb
|
|
1430
1434
|
==> 2
|
1431
1435
|
```
|
1432
1436
|
|
1433
|
-
|
1437
|
+
Now let's make use of our domain mapper in a command, which is its intended purpose:
|
1438
|
+
|
1439
|
+
```ruby
|
1440
|
+
|
1441
|
+
```
|
1434
1442
|
|
1435
1443
|
```irb
|
1436
1444
|
> FoobaraDemo::CapyCafe::IncrementAge.run!(capybara: barbara)
|
@@ -1444,33 +1452,6 @@ And we can increment Barbara's age now that she has been imported into our CapyC
|
|
1444
1452
|
Now let's create a command that makes use of our domain mapper which is the typical usage pattern:
|
1445
1453
|
|
1446
1454
|
```ruby
|
1447
|
-
#!/usr/bin/env ruby
|
1448
|
-
|
1449
|
-
require "foobara/remote_imports"
|
1450
|
-
|
1451
|
-
[9292, 9293].each do |port|
|
1452
|
-
Foobara::RemoteImports::ImportCommand.run!(manifest_url: "http://localhost:#{port}/manifest")
|
1453
|
-
end
|
1454
|
-
|
1455
|
-
module FoobaraDemo
|
1456
|
-
module AnimalHouse
|
1457
|
-
foobara_domain!
|
1458
|
-
end
|
1459
|
-
end
|
1460
|
-
|
1461
|
-
module FoobaraDemo
|
1462
|
-
module AnimalHouse
|
1463
|
-
class Animal < Foobara::Model
|
1464
|
-
attributes do
|
1465
|
-
first_name :string
|
1466
|
-
last_name :string
|
1467
|
-
birthday :date
|
1468
|
-
species :symbol, one_of: %i[capybara cat tartigrade]
|
1469
|
-
end
|
1470
|
-
end
|
1471
|
-
end
|
1472
|
-
end
|
1473
|
-
|
1474
1455
|
module FoobaraDemo
|
1475
1456
|
module CapyCafe
|
1476
1457
|
class ImportAnimal < Foobara::Command
|
@@ -1487,7 +1468,7 @@ module FoobaraDemo
|
|
1487
1468
|
|
1488
1469
|
possible_input_error :animal, NotACapybara
|
1489
1470
|
|
1490
|
-
depends_on CreateCapybara
|
1471
|
+
depends_on CreateCapybara, DomainMappers::MapAnimalToCapybara
|
1491
1472
|
|
1492
1473
|
def execute
|
1493
1474
|
create_capybara
|
@@ -1497,14 +1478,6 @@ module FoobaraDemo
|
|
1497
1478
|
|
1498
1479
|
attr_accessor :capybara
|
1499
1480
|
|
1500
|
-
def validate
|
1501
|
-
species = animal.species
|
1502
|
-
|
1503
|
-
unless species == :capybara
|
1504
|
-
add_input_error :animal, NotACapybara, animal: animal, species: species
|
1505
|
-
end
|
1506
|
-
end
|
1507
|
-
|
1508
1481
|
def create_capybara
|
1509
1482
|
self.capybara = run_mapped_subcommand!(CreateCapybara, animal)
|
1510
1483
|
end
|
@@ -1518,8 +1491,17 @@ Note that we can automatically map `animal` to CreateCapybara inputs by calling
|
|
1518
1491
|
Let's play with it:
|
1519
1492
|
|
1520
1493
|
```irb
|
1521
|
-
|
1494
|
+
$ ./animal_house_import.rb
|
1495
|
+
> basil = FoobaraDemo::CapyCafe::ImportAnimal.run!(animal: { species: :capybara, first_name: "Basil", last_name: "Doe", birthday: "1000-01-01" })
|
1496
|
+
==> <Capybara:3>
|
1497
|
+
> FoobaraDemo::CapyCafe::FindCapybara.run!(id: basil).age
|
1498
|
+
==> 1024
|
1499
|
+
> FoobaraDemo::CapyCafe::IncrementAge.run!(capybara: basil)
|
1500
|
+
==> <Capybara:3>
|
1501
|
+
> FoobaraDemo::CapyCafe::FindCapybara.run!(id: basil).age
|
1502
|
+
==> 1025
|
1522
1503
|
```
|
1504
|
+
|
1523
1505
|
TODO
|
1524
1506
|
|
1525
1507
|
### Code Generators
|
@@ -2,34 +2,124 @@ module Foobara
|
|
2
2
|
class Command
|
3
3
|
module Concerns
|
4
4
|
module DomainMappers
|
5
|
+
class ForgotToDependOnDomainMapperError < Foobara::RuntimeError
|
6
|
+
context { mapper_name :string, :required }
|
7
|
+
|
8
|
+
attr_accessor :mapper
|
9
|
+
|
10
|
+
def initialize(mapper)
|
11
|
+
self.mapper = mapper
|
12
|
+
super()
|
13
|
+
end
|
14
|
+
|
15
|
+
def context
|
16
|
+
{ mapper_name: mapper.name }
|
17
|
+
end
|
18
|
+
|
19
|
+
def message
|
20
|
+
"Did you maybe forget to add depends_on #{mapper.name}?"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class NoDomainMapperFoundError < Foobara::RuntimeError
|
25
|
+
context do
|
26
|
+
subcommand_name :string, :required
|
27
|
+
to :duck
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_accessor :subcommand, :to
|
31
|
+
|
32
|
+
def initialize(subcommand, to)
|
33
|
+
self.subcommand = subcommand
|
34
|
+
self.to = to
|
35
|
+
|
36
|
+
super()
|
37
|
+
end
|
38
|
+
|
39
|
+
def context
|
40
|
+
{ subcommand_name: subcommand.name, to: }
|
41
|
+
end
|
42
|
+
|
43
|
+
def message
|
44
|
+
"No DomainMapper found that maps to #{subcommand.name} or from its result"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
5
48
|
include Concern
|
6
49
|
|
7
|
-
def run_mapped_subcommand!(subcommand_class,
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
50
|
+
def run_mapped_subcommand!(subcommand_class, unmapped_inputs = {}, to = nil)
|
51
|
+
mapped_something = false
|
52
|
+
no_mapper_found = nil
|
53
|
+
|
54
|
+
criteria = ->(mapper) { self.class.depends_on?(mapper) }
|
55
|
+
|
56
|
+
inputs_mapper = self.class.domain.lookup_matching_domain_mapper(
|
57
|
+
from: unmapped_inputs,
|
58
|
+
to: subcommand_class,
|
59
|
+
criteria:,
|
60
|
+
strict: true
|
61
|
+
)
|
62
|
+
|
63
|
+
inputs = if inputs_mapper
|
64
|
+
mapped_something = true
|
65
|
+
run_subcommand!(inputs_mapper, from: unmapped_inputs)
|
66
|
+
else
|
67
|
+
unmapped_inputs
|
68
|
+
end
|
69
|
+
|
70
|
+
result_mapper = if subcommand_class.result_type
|
71
|
+
mapper = self.class.domain.lookup_matching_domain_mapper(
|
72
|
+
from: subcommand_class.result_type,
|
73
|
+
to:,
|
74
|
+
criteria:,
|
75
|
+
strict: true
|
76
|
+
)
|
20
77
|
|
21
|
-
|
78
|
+
no_mapper_found = mapper.nil? && inputs_mapper.nil?
|
22
79
|
|
23
|
-
|
80
|
+
mapper
|
81
|
+
end
|
24
82
|
|
25
|
-
|
26
|
-
|
83
|
+
result = unless no_mapper_found
|
84
|
+
run_subcommand!(subcommand_class, inputs)
|
85
|
+
end
|
86
|
+
|
87
|
+
unless subcommand_class.result_type
|
88
|
+
result_mapper = self.class.domain.lookup_matching_domain_mapper(
|
27
89
|
from: result,
|
28
|
-
to
|
90
|
+
to:,
|
91
|
+
criteria: ->(domain_mapper) { self.class.depends_on?(domain_mapper) },
|
29
92
|
strict: true
|
30
93
|
)
|
94
|
+
end
|
95
|
+
|
96
|
+
if result_mapper
|
97
|
+
mapped_something = true
|
98
|
+
result = run_subcommand!(result_mapper, from: result)
|
99
|
+
end
|
100
|
+
|
101
|
+
unless mapped_something
|
102
|
+
mapper = self.class.domain.lookup_matching_domain_mapper(
|
103
|
+
from: unmapped_inputs,
|
104
|
+
to: subcommand_class,
|
105
|
+
strict: true
|
106
|
+
)
|
107
|
+
|
108
|
+
if mapper
|
109
|
+
raise ForgotToDependOnDomainMapperError, mapper
|
110
|
+
end
|
111
|
+
|
112
|
+
mapper = self.class.domain.lookup_matching_domain_mapper(
|
113
|
+
from: subcommand_class.result_type,
|
114
|
+
to:,
|
115
|
+
strict: true
|
116
|
+
)
|
117
|
+
|
118
|
+
if mapper
|
119
|
+
raise ForgotToDependOnDomainMapperError, mapper
|
120
|
+
end
|
31
121
|
|
32
|
-
|
122
|
+
raise NoDomainMapperFoundError.new(subcommand_class, to)
|
33
123
|
end
|
34
124
|
|
35
125
|
result
|
@@ -14,12 +14,6 @@ module Foobara
|
|
14
14
|
Namespace.global.foobara_add_category(:organization) { is_a?(Module) && foobara_organization? }
|
15
15
|
Namespace.global.foobara_add_category(:domain) { is_a?(Module) && foobara_domain? }
|
16
16
|
end
|
17
|
-
|
18
|
-
def reset_all
|
19
|
-
if Foobara::DomainMapper.instance_variable_defined?(:@foobara_domain_mappers_to_process)
|
20
|
-
Foobara::DomainMapper.remove_instance_variable(:@foobara_domain_mappers_to_process)
|
21
|
-
end
|
22
|
-
end
|
23
17
|
end
|
24
18
|
end
|
25
19
|
end
|
@@ -148,27 +148,19 @@ module Foobara
|
|
148
148
|
value
|
149
149
|
end
|
150
150
|
|
151
|
-
mapper =
|
151
|
+
mapper = lookup_matching_domain_mapper(from:, to:, strict:)
|
152
152
|
|
153
|
-
mapper&.
|
153
|
+
mapper&.map!(value)
|
154
154
|
end
|
155
155
|
|
156
156
|
def foobara_domain_map!(value, from: value, to: nil, strict: false)
|
157
|
-
mapper =
|
157
|
+
mapper = lookup_matching_domain_mapper(from:, to:, strict:)
|
158
|
+
|
158
159
|
unless mapper
|
159
|
-
raise Foobara::
|
160
|
+
raise Foobara::DomainMapperLookups::NoDomainMapperFoundError.new(from, to, value:)
|
160
161
|
end
|
161
162
|
|
162
|
-
mapper.
|
163
|
-
end
|
164
|
-
|
165
|
-
def foobara_domain_mapper(mapper)
|
166
|
-
foobara_domain_mapper_registry(skip_check: true).register(mapper)
|
167
|
-
end
|
168
|
-
|
169
|
-
def foobara_domain_mapper_registry(skip_check: false)
|
170
|
-
Foobara::DomainMapper.foobara_process_domain_mappers unless skip_check
|
171
|
-
@foobara_domain_mapper_registry ||= DomainMapper::Registry.new
|
163
|
+
mapper.map!(value)
|
172
164
|
end
|
173
165
|
|
174
166
|
def foobara_domain_name
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Foobara
|
2
|
+
# TODO: would be nice to inherit from something other than Command. Can we hoist a bunch of common behavior up
|
3
|
+
# out of Command into some other class maybe called Service or Runnable or something?
|
4
|
+
class DomainMapper < Foobara::Command
|
5
|
+
class << self
|
6
|
+
def map(value)
|
7
|
+
new(from: value).run
|
8
|
+
end
|
9
|
+
|
10
|
+
def map!(value)
|
11
|
+
new(from: value).run!
|
12
|
+
end
|
13
|
+
|
14
|
+
# A bit hacky because Command only supports attributes inputs at the moment, ugg.
|
15
|
+
def from(...)
|
16
|
+
from_type = args_to_type(...)
|
17
|
+
|
18
|
+
inputs do
|
19
|
+
from from_type, :required
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def to(...)
|
24
|
+
result_type = args_to_type(...)
|
25
|
+
result(result_type)
|
26
|
+
end
|
27
|
+
|
28
|
+
def from_type
|
29
|
+
inputs_type.element_types[:from]
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_type
|
33
|
+
result_type
|
34
|
+
end
|
35
|
+
|
36
|
+
def applicable?(from_value, to_value)
|
37
|
+
matches?(from_type, from_value) && matches?(to_type, to_value)
|
38
|
+
end
|
39
|
+
|
40
|
+
def matches?(type_indicator, value)
|
41
|
+
return true if type_indicator.nil? || value.nil? || type_indicator == value
|
42
|
+
|
43
|
+
type = object_to_type(type_indicator)
|
44
|
+
|
45
|
+
return true if type.nil? || type == value
|
46
|
+
return true if type.applicable?(value) && type.process_value(value).success?
|
47
|
+
|
48
|
+
if value.is_a?(Types::Type)
|
49
|
+
if !value.registered? && !type.registered?
|
50
|
+
value.declaration_data == type.declaration_data
|
51
|
+
end
|
52
|
+
else
|
53
|
+
value_type = object_to_type(value)
|
54
|
+
|
55
|
+
if value_type
|
56
|
+
matches?(type, value_type)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# TODO: should this be somewhere more general-purpose?
|
62
|
+
def args_to_type(*args, **opts, &block)
|
63
|
+
if args.size == 1 && opts.empty? && block.nil?
|
64
|
+
object_to_type(args.first)
|
65
|
+
else
|
66
|
+
domain.foobara_type_from_declaration(*args, **opts, &block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def object_to_type(object)
|
71
|
+
if object
|
72
|
+
if object.is_a?(::Class)
|
73
|
+
if object < Foobara::Model
|
74
|
+
object.model_type
|
75
|
+
elsif object < Foobara::Command
|
76
|
+
object.inputs_type
|
77
|
+
else
|
78
|
+
domain.foobara_type_from_declaration(object)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
case object
|
82
|
+
when Types::Type
|
83
|
+
object
|
84
|
+
when ::Symbol
|
85
|
+
domain.foobara_lookup_type!(object)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def execute
|
93
|
+
map
|
94
|
+
end
|
95
|
+
|
96
|
+
def from
|
97
|
+
inputs[:from]
|
98
|
+
end
|
99
|
+
|
100
|
+
def map
|
101
|
+
# :nocov:
|
102
|
+
raise "subclass responsibility"
|
103
|
+
# :nocov:
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/projects/{domain/src/domain_mapper/registry.rb → domain_mapper/src/domain_mapper_lookups.rb}
RENAMED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Foobara
|
2
|
-
|
2
|
+
module DomainMapperLookups
|
3
3
|
class NoDomainMapperFoundError < StandardError
|
4
4
|
attr_accessor :value, :from, :to, :has_value
|
5
5
|
|
@@ -25,31 +25,33 @@ module Foobara
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
class
|
29
|
-
|
30
|
-
attr_accessor :candidates, :from, :to
|
28
|
+
class AmbiguousDomainMapperError < StandardError
|
29
|
+
attr_accessor :candidates, :from, :to
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
def initialize(from, to, candidates)
|
32
|
+
self.to = to
|
33
|
+
self.from = from
|
34
|
+
self.candidates = [*candidates].flatten
|
36
35
|
|
37
|
-
|
38
|
-
end
|
36
|
+
super("#{candidates.size} ambiguous candidates found.")
|
39
37
|
end
|
38
|
+
end
|
40
39
|
|
41
|
-
|
42
|
-
mappers << mapper
|
43
|
-
end
|
40
|
+
include Concern
|
44
41
|
|
45
|
-
|
46
|
-
|
42
|
+
module ClassMethods
|
43
|
+
def lookup_matching_domain_mapper!(from: nil, to: nil, strict: false, criteria: nil)
|
44
|
+
result = lookup_matching_domain_mapper(from:, to:, strict:, criteria:)
|
47
45
|
|
48
46
|
result || raise(NoDomainMapperFoundError.new(from, to))
|
49
47
|
end
|
50
48
|
|
51
|
-
def
|
49
|
+
def lookup_matching_domain_mapper(from: nil, to: nil, strict: false, criteria: nil)
|
52
50
|
candidates = mappers.select do |mapper|
|
51
|
+
if criteria
|
52
|
+
next unless criteria.call(mapper)
|
53
|
+
end
|
54
|
+
|
53
55
|
mapper.applicable?(from, to)
|
54
56
|
end
|
55
57
|
|
@@ -63,15 +65,15 @@ module Foobara
|
|
63
65
|
|
64
66
|
unless strict
|
65
67
|
if from
|
66
|
-
|
68
|
+
lookup_matching_domain_mapper(from: nil, to:)
|
67
69
|
elsif to
|
68
|
-
|
70
|
+
lookup_matching_domain_mapper(from:, to: nil)
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
73
75
|
def mappers
|
74
|
-
@mappers ||=
|
76
|
+
@mappers ||= foobara_all_domain_mapper
|
75
77
|
end
|
76
78
|
end
|
77
79
|
end
|
@@ -18,12 +18,11 @@ module Foobara
|
|
18
18
|
"state_machine",
|
19
19
|
"namespace"
|
20
20
|
|
21
|
-
project "domain"
|
22
|
-
|
23
21
|
# various components of the foobara framework that have some level of coupling.
|
24
22
|
# for example, Error in common knows about (or could be implemented to know about)
|
25
23
|
# type declarations to expose its context type.
|
26
|
-
projects "
|
24
|
+
projects "domain",
|
25
|
+
"common",
|
27
26
|
"value",
|
28
27
|
"types",
|
29
28
|
"type_declarations",
|
@@ -32,6 +31,7 @@ module Foobara
|
|
32
31
|
"detached_entity",
|
33
32
|
"entity",
|
34
33
|
"command",
|
34
|
+
"domain_mapper",
|
35
35
|
"persistence",
|
36
36
|
"in_memory_crud_driver_minimal",
|
37
37
|
"in_memory_crud_driver",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foobara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.38
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: foobara-util
|
@@ -193,8 +193,6 @@ files:
|
|
193
193
|
- projects/detached_entity/src/extensions/type_declarations/handlers/extend_detached_entity_type_declaration/validate_primary_key_references_attribute.rb
|
194
194
|
- projects/domain/lib/foobara/domain.rb
|
195
195
|
- projects/domain/src/domain.rb
|
196
|
-
- projects/domain/src/domain_mapper.rb
|
197
|
-
- projects/domain/src/domain_mapper/registry.rb
|
198
196
|
- projects/domain/src/domain_module_extension.rb
|
199
197
|
- projects/domain/src/extensions/foobara.rb
|
200
198
|
- projects/domain/src/global_domain.rb
|
@@ -204,6 +202,9 @@ files:
|
|
204
202
|
- projects/domain/src/module_extension.rb
|
205
203
|
- projects/domain/src/organization.rb
|
206
204
|
- projects/domain/src/organization_module_extension.rb
|
205
|
+
- projects/domain_mapper/lib/foobara/domain_mapper.rb
|
206
|
+
- projects/domain_mapper/src/domain_mapper.rb
|
207
|
+
- projects/domain_mapper/src/domain_mapper_lookups.rb
|
207
208
|
- projects/entity/lib/foobara/entity.rb
|
208
209
|
- projects/entity/src/concerns/attribute_helpers.rb
|
209
210
|
- projects/entity/src/concerns/attributes.rb
|
@@ -393,6 +394,7 @@ require_paths:
|
|
393
394
|
- "./projects/delegate/lib"
|
394
395
|
- "./projects/detached_entity/lib"
|
395
396
|
- "./projects/domain/lib"
|
397
|
+
- "./projects/domain_mapper/lib"
|
396
398
|
- "./projects/entity/lib"
|
397
399
|
- "./projects/enumerated/lib"
|
398
400
|
- "./projects/foobara/lib"
|
@@ -1,166 +0,0 @@
|
|
1
|
-
module Foobara
|
2
|
-
class DomainMapper
|
3
|
-
class << self
|
4
|
-
def call(value)
|
5
|
-
instance.call(value)
|
6
|
-
end
|
7
|
-
|
8
|
-
def from(*args)
|
9
|
-
if args.empty?
|
10
|
-
@from
|
11
|
-
else
|
12
|
-
if args.size > 1
|
13
|
-
# :nocov:
|
14
|
-
raise ArgumentError, "only one argument allowed"
|
15
|
-
# :nocov:
|
16
|
-
end
|
17
|
-
|
18
|
-
@from = args.first
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def to(*args)
|
23
|
-
if args.empty?
|
24
|
-
@to
|
25
|
-
else
|
26
|
-
if args.size > 1
|
27
|
-
# :nocov:
|
28
|
-
raise ArgumentError, "only one argument allowed"
|
29
|
-
# :nocov:
|
30
|
-
end
|
31
|
-
|
32
|
-
@to = args.first
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def from_type
|
37
|
-
return @from_type if defined?(@from_type)
|
38
|
-
|
39
|
-
@from_type = object_to_type(from)
|
40
|
-
end
|
41
|
-
|
42
|
-
def to_type
|
43
|
-
return @to_type if defined?(@to_type)
|
44
|
-
|
45
|
-
@to_type = object_to_type(to)
|
46
|
-
end
|
47
|
-
|
48
|
-
def instance
|
49
|
-
@instance ||= new
|
50
|
-
end
|
51
|
-
|
52
|
-
def inherited(subclass)
|
53
|
-
foobara_domain_mapper_to_process(subclass.instance)
|
54
|
-
|
55
|
-
super
|
56
|
-
end
|
57
|
-
|
58
|
-
def foobara_domain_mapper_to_process(mapper)
|
59
|
-
foobara_domain_mappers_to_process << mapper
|
60
|
-
end
|
61
|
-
|
62
|
-
def foobara_domain_mappers_to_process
|
63
|
-
@foobara_domain_mappers_to_process ||= []
|
64
|
-
end
|
65
|
-
|
66
|
-
def foobara_process_domain_mappers
|
67
|
-
if defined?(@foobara_domain_mappers_to_process)
|
68
|
-
@foobara_domain_mappers_to_process.each do |mapper|
|
69
|
-
mapper.domain.foobara_domain_mapper(mapper)
|
70
|
-
end
|
71
|
-
remove_instance_variable(:@foobara_domain_mappers_to_process)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def domain
|
76
|
-
candidate = self
|
77
|
-
|
78
|
-
loop do
|
79
|
-
candidate = Util.module_for(candidate)
|
80
|
-
|
81
|
-
if candidate.nil?
|
82
|
-
# :nocov:
|
83
|
-
raise "Domain mapper must be scoped within a domain but #{self.class.name} is not in a domain"
|
84
|
-
# :nocov:
|
85
|
-
elsif candidate.foobara_domain?
|
86
|
-
return candidate
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def matches?(type_indicator, value)
|
92
|
-
return true if type_indicator.nil? || value.nil? || type_indicator == value
|
93
|
-
|
94
|
-
type = object_to_type(type_indicator)
|
95
|
-
|
96
|
-
return true if type.nil? || type == value
|
97
|
-
return true if type.applicable?(value) && type.process_value(value).success?
|
98
|
-
|
99
|
-
if value.is_a?(Types::Type)
|
100
|
-
if !value.registered? && !type.registered?
|
101
|
-
value.declaration_data == type.declaration_data
|
102
|
-
end
|
103
|
-
else
|
104
|
-
value_type = object_to_type(value)
|
105
|
-
|
106
|
-
if value_type
|
107
|
-
matches?(type, value_type)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def object_to_type(object)
|
113
|
-
if object
|
114
|
-
if object.is_a?(::Class)
|
115
|
-
if object < Foobara::Model
|
116
|
-
object.model_type
|
117
|
-
elsif object < Foobara::Command
|
118
|
-
object.inputs_type
|
119
|
-
else
|
120
|
-
domain.foobara_type_from_declaration(object)
|
121
|
-
end
|
122
|
-
else
|
123
|
-
case object
|
124
|
-
when Types::Type
|
125
|
-
object
|
126
|
-
when ::Symbol
|
127
|
-
domain.foobara_lookup_type!(object)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def from_type
|
135
|
-
self.class.from_type
|
136
|
-
end
|
137
|
-
|
138
|
-
def to_type
|
139
|
-
self.class.to_type
|
140
|
-
end
|
141
|
-
|
142
|
-
def call(from_value)
|
143
|
-
from_value = from_type.process_value!(from_value)
|
144
|
-
|
145
|
-
mapped_value = map(from_value)
|
146
|
-
|
147
|
-
to_type.process_value!(mapped_value)
|
148
|
-
end
|
149
|
-
|
150
|
-
# TODO: can we make _from_value passed to #initialize instead? That way it doesn't have to be passed around
|
151
|
-
# between various helper methods
|
152
|
-
def map(_from_value)
|
153
|
-
# :nocov:
|
154
|
-
raise "subclass repsonsibility"
|
155
|
-
# :nocov:
|
156
|
-
end
|
157
|
-
|
158
|
-
def applicable?(from_value, to_value)
|
159
|
-
self.class.matches?(from_type, from_value) && self.class.matches?(to_type, to_value)
|
160
|
-
end
|
161
|
-
|
162
|
-
def domain
|
163
|
-
self.class.domain
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|