rom 5.4.2 → 6.0.0.alpha1
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 +58 -71
- data/LICENSE +1 -1
- data/README.md +7 -6
- data/lib/rom/array_dataset.rb +46 -0
- data/lib/rom/associations/abstract.rb +217 -0
- data/lib/rom/associations/definitions/abstract.rb +150 -0
- data/lib/rom/associations/definitions/many_to_many.rb +29 -0
- data/lib/rom/associations/definitions/many_to_one.rb +14 -0
- data/lib/rom/associations/definitions/one_to_many.rb +14 -0
- data/lib/rom/associations/definitions/one_to_one.rb +14 -0
- data/lib/rom/associations/definitions/one_to_one_through.rb +14 -0
- data/lib/rom/associations/definitions.rb +7 -0
- data/lib/rom/associations/many_to_many.rb +128 -0
- data/lib/rom/associations/many_to_one.rb +65 -0
- data/lib/rom/associations/one_to_many.rb +65 -0
- data/lib/rom/associations/one_to_one.rb +13 -0
- data/lib/rom/associations/one_to_one_through.rb +13 -0
- data/lib/rom/associations/through_identifier.rb +41 -0
- data/lib/rom/attribute.rb +425 -0
- data/lib/rom/auto_curry.rb +70 -0
- data/lib/rom/cache.rb +87 -0
- data/lib/rom/changeset/associated.rb +110 -0
- data/lib/rom/changeset/create.rb +18 -0
- data/lib/rom/changeset/delete.rb +15 -0
- data/lib/rom/changeset/extensions/relation.rb +26 -0
- data/lib/rom/changeset/pipe.rb +81 -0
- data/lib/rom/changeset/pipe_registry.rb +27 -0
- data/lib/rom/changeset/stateful.rb +285 -0
- data/lib/rom/changeset/update.rb +81 -0
- data/lib/rom/changeset.rb +185 -0
- data/lib/rom/command.rb +351 -0
- data/lib/rom/command_compiler.rb +201 -0
- data/lib/rom/command_proxy.rb +36 -0
- data/lib/rom/commands/class_interface.rb +236 -0
- data/lib/rom/commands/composite.rb +55 -0
- data/lib/rom/commands/create.rb +15 -0
- data/lib/rom/commands/delete.rb +16 -0
- data/lib/rom/commands/graph/class_interface.rb +64 -0
- data/lib/rom/commands/graph/input_evaluator.rb +94 -0
- data/lib/rom/commands/graph.rb +88 -0
- data/lib/rom/commands/lazy/create.rb +35 -0
- data/lib/rom/commands/lazy/delete.rb +39 -0
- data/lib/rom/commands/lazy/update.rb +46 -0
- data/lib/rom/commands/lazy.rb +106 -0
- data/lib/rom/commands/update.rb +16 -0
- data/lib/rom/commands.rb +5 -0
- data/lib/rom/compat/auto_registration.rb +115 -0
- data/lib/rom/compat/auto_registration_strategies/base.rb +29 -0
- data/lib/rom/compat/auto_registration_strategies/custom_namespace.rb +84 -0
- data/lib/rom/compat/auto_registration_strategies/no_namespace.rb +33 -0
- data/lib/rom/compat/auto_registration_strategies/with_namespace.rb +29 -0
- data/lib/rom/compat/command.rb +74 -0
- data/lib/rom/compat/components/dsl/schema.rb +130 -0
- data/lib/rom/compat/components.rb +91 -0
- data/lib/rom/compat/global.rb +17 -0
- data/lib/rom/compat/mapper.rb +22 -0
- data/lib/rom/compat/registries.rb +47 -0
- data/lib/rom/compat/relation.rb +40 -0
- data/lib/rom/compat/schema/dsl.rb +260 -0
- data/lib/rom/compat/setting_proxy.rb +44 -0
- data/lib/rom/compat/setup.rb +151 -0
- data/lib/rom/compat/transformer.rb +49 -0
- data/lib/rom/compat.rb +22 -0
- data/lib/rom/components/association.rb +26 -0
- data/lib/rom/components/command.rb +24 -0
- data/lib/rom/components/core.rb +148 -0
- data/lib/rom/components/dataset.rb +60 -0
- data/lib/rom/components/dsl/association.rb +47 -0
- data/lib/rom/components/dsl/command.rb +60 -0
- data/lib/rom/components/dsl/core.rb +126 -0
- data/lib/rom/components/dsl/dataset.rb +33 -0
- data/lib/rom/components/dsl/gateway.rb +14 -0
- data/lib/rom/components/dsl/mapper.rb +70 -0
- data/lib/rom/components/dsl/relation.rb +49 -0
- data/lib/rom/components/dsl/schema.rb +150 -0
- data/lib/rom/components/dsl/view.rb +82 -0
- data/lib/rom/components/dsl.rb +255 -0
- data/lib/rom/components/gateway.rb +50 -0
- data/lib/rom/components/mapper.rb +29 -0
- data/lib/rom/components/provider.rb +160 -0
- data/lib/rom/components/registry.rb +154 -0
- data/lib/rom/components/relation.rb +41 -0
- data/lib/rom/components/schema.rb +61 -0
- data/lib/rom/components/view.rb +55 -0
- data/lib/rom/components.rb +55 -0
- data/lib/rom/configuration_dsl.rb +4 -0
- data/lib/rom/constants.rb +135 -0
- data/lib/rom/container.rb +182 -0
- data/lib/rom/core.rb +125 -0
- data/lib/rom/data_proxy.rb +97 -0
- data/lib/rom/enumerable_dataset.rb +70 -0
- data/lib/rom/gateway.rb +232 -0
- data/lib/rom/global.rb +56 -0
- data/lib/rom/header/attribute.rb +190 -0
- data/lib/rom/header.rb +198 -0
- data/lib/rom/inferrer.rb +55 -0
- data/lib/rom/initializer.rb +80 -0
- data/lib/rom/lint/enumerable_dataset.rb +56 -0
- data/lib/rom/lint/gateway.rb +120 -0
- data/lib/rom/lint/linter.rb +79 -0
- data/lib/rom/lint/spec.rb +22 -0
- data/lib/rom/lint/test.rb +98 -0
- data/lib/rom/loader.rb +161 -0
- data/lib/rom/mapper/attribute_dsl.rb +480 -0
- data/lib/rom/mapper/dsl.rb +107 -0
- data/lib/rom/mapper/model_dsl.rb +61 -0
- data/lib/rom/mapper.rb +99 -0
- data/lib/rom/mapper_compiler.rb +84 -0
- data/lib/rom/memory/associations/many_to_many.rb +12 -0
- data/lib/rom/memory/associations/many_to_one.rb +12 -0
- data/lib/rom/memory/associations/one_to_many.rb +12 -0
- data/lib/rom/memory/associations/one_to_one.rb +12 -0
- data/lib/rom/memory/associations.rb +6 -0
- data/lib/rom/memory/commands.rb +60 -0
- data/lib/rom/memory/dataset.rb +127 -0
- data/lib/rom/memory/gateway.rb +66 -0
- data/lib/rom/memory/mapper_compiler.rb +10 -0
- data/lib/rom/memory/relation.rb +91 -0
- data/lib/rom/memory/schema.rb +32 -0
- data/lib/rom/memory/storage.rb +61 -0
- data/lib/rom/memory/types.rb +11 -0
- data/lib/rom/memory.rb +7 -0
- data/lib/rom/model_builder.rb +103 -0
- data/lib/rom/open_struct.rb +112 -0
- data/lib/rom/pipeline.rb +111 -0
- data/lib/rom/plugin.rb +130 -0
- data/lib/rom/plugins/class_methods.rb +37 -0
- data/lib/rom/plugins/command/schema.rb +45 -0
- data/lib/rom/plugins/command/timestamps.rb +149 -0
- data/lib/rom/plugins/dsl.rb +53 -0
- data/lib/rom/plugins/relation/changeset.rb +97 -0
- data/lib/rom/plugins/relation/instrumentation.rb +66 -0
- data/lib/rom/plugins/relation/registry_reader.rb +36 -0
- data/lib/rom/plugins/schema/timestamps.rb +59 -0
- data/lib/rom/plugins.rb +100 -0
- data/lib/rom/processor/composer.rb +37 -0
- data/lib/rom/processor/transformer.rb +415 -0
- data/lib/rom/processor.rb +30 -0
- data/lib/rom/registries/associations.rb +26 -0
- data/lib/rom/registries/commands.rb +11 -0
- data/lib/rom/registries/container.rb +12 -0
- data/lib/rom/registries/datasets.rb +21 -0
- data/lib/rom/registries/gateways.rb +8 -0
- data/lib/rom/registries/mappers.rb +21 -0
- data/lib/rom/registries/nestable.rb +32 -0
- data/lib/rom/registries/relations.rb +8 -0
- data/lib/rom/registries/root.rb +203 -0
- data/lib/rom/registries/schemas.rb +44 -0
- data/lib/rom/registries/views.rb +11 -0
- data/lib/rom/relation/class_interface.rb +61 -0
- data/lib/rom/relation/combined.rb +160 -0
- data/lib/rom/relation/commands.rb +65 -0
- data/lib/rom/relation/composite.rb +53 -0
- data/lib/rom/relation/curried.rb +129 -0
- data/lib/rom/relation/graph.rb +107 -0
- data/lib/rom/relation/loaded.rb +136 -0
- data/lib/rom/relation/materializable.rb +62 -0
- data/lib/rom/relation/name.rb +122 -0
- data/lib/rom/relation/wrap.rb +64 -0
- data/lib/rom/relation.rb +625 -0
- data/lib/rom/repository/class_interface.rb +162 -0
- data/lib/rom/repository/relation_reader.rb +48 -0
- data/lib/rom/repository/root.rb +75 -0
- data/lib/rom/repository/session.rb +60 -0
- data/lib/rom/repository.rb +179 -0
- data/lib/rom/schema/associations_dsl.rb +222 -0
- data/lib/rom/schema/inferrer.rb +106 -0
- data/lib/rom/schema.rb +471 -0
- data/lib/rom/settings.rb +141 -0
- data/lib/rom/setup.rb +297 -0
- data/lib/rom/struct.rb +99 -0
- data/lib/rom/struct_compiler.rb +114 -0
- data/lib/rom/support/configurable.rb +213 -0
- data/lib/rom/support/inflector.rb +31 -0
- data/lib/rom/support/memoizable.rb +61 -0
- data/lib/rom/support/notifications.rb +238 -0
- data/lib/rom/transaction.rb +26 -0
- data/lib/rom/transformer.rb +46 -0
- data/lib/rom/types.rb +74 -0
- data/lib/rom/version.rb +1 -1
- data/lib/rom-changeset.rb +4 -0
- data/lib/rom-core.rb +3 -0
- data/lib/rom-repository.rb +4 -0
- data/lib/rom.rb +3 -3
- metadata +302 -23
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/cache"
|
4
|
+
|
5
|
+
require "rom/repository/relation_reader"
|
6
|
+
|
7
|
+
module ROM
|
8
|
+
class Repository
|
9
|
+
# Class-level APIs for repositories
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
module ClassInterface
|
13
|
+
# Create a root-repository class and set its root relation
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# # where :users is the relation name in your rom container
|
17
|
+
# class UserRepo < ROM::Repository[:users]
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @param name [Symbol] The relation `register_as` value
|
21
|
+
#
|
22
|
+
# @return [Class] descendant of ROM::Repository::Root
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
def [](name)
|
26
|
+
fetch_or_store(name) do
|
27
|
+
klass = Class.new(self < Repository::Root ? self : Repository::Root)
|
28
|
+
klass.root(name)
|
29
|
+
klass
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Initialize a new repository object, establishing configured relation proxies from
|
34
|
+
# the passed container
|
35
|
+
#
|
36
|
+
# @overload new(container, **options)
|
37
|
+
# Initialize with container as leading parameter
|
38
|
+
#
|
39
|
+
# @param [ROM::Container] container Finalized rom container
|
40
|
+
#
|
41
|
+
# @param [Hash] options Repository options
|
42
|
+
# @option options [Module] :struct_namespace Custom struct namespace
|
43
|
+
# @option options [Boolean] :auto_struct Enable/Disable auto-struct mapping
|
44
|
+
#
|
45
|
+
# @overload new(**options)
|
46
|
+
# Inititalize with container as option
|
47
|
+
#
|
48
|
+
# @param [Hash] options Repository options
|
49
|
+
# @option options [ROM::Container] :container Finalized rom container
|
50
|
+
# @option options [Module] :struct_namespace Custom struct namespace
|
51
|
+
# @option options [Boolean] :auto_struct Enable/Disable auto-struct mapping
|
52
|
+
#
|
53
|
+
# @api public
|
54
|
+
def new(container = nil, **options)
|
55
|
+
container ||= options.fetch(:container)
|
56
|
+
|
57
|
+
unless relation_reader
|
58
|
+
relation_reader(RelationReader.new(self, container.relation_ids))
|
59
|
+
include(relation_reader)
|
60
|
+
end
|
61
|
+
|
62
|
+
super(**options, container: container)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Inherits configured relations and commands
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
def inherited(klass)
|
69
|
+
super
|
70
|
+
|
71
|
+
return if equal?(Repository)
|
72
|
+
|
73
|
+
klass.extend(::Dry::Core::Cache)
|
74
|
+
klass.commands(*commands)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Defines command methods on a root repository
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# class UserRepo < ROM::Repository[:users]
|
81
|
+
# commands :create, update: :by_pk, delete: :by_pk
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# # with custom command plugin
|
85
|
+
# class UserRepo < ROM::Repository[:users]
|
86
|
+
# commands :create, use: :my_command_plugin
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# # with custom mapper
|
90
|
+
# class UserRepo < ROM::Repository[:users]
|
91
|
+
# commands :create, mapper: :my_custom_mapper
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# @param [Array<Symbol>] names A list of command names
|
95
|
+
# @option :mapper [Symbol] An optional mapper identifier
|
96
|
+
# @option :use [Symbol] An optional command plugin identifier
|
97
|
+
#
|
98
|
+
# @return [Array<Symbol>] A list of defined command names
|
99
|
+
#
|
100
|
+
# @api public
|
101
|
+
def commands(*names, mapper: nil, use: nil, plugins_options: EMPTY_HASH, **opts)
|
102
|
+
if names.any? || opts.any?
|
103
|
+
@commands = names + opts.to_a
|
104
|
+
|
105
|
+
@commands.each do |spec|
|
106
|
+
type, *view = Array(spec).flatten
|
107
|
+
|
108
|
+
if view.empty?
|
109
|
+
define_command_method(type, mapper: mapper, use: use,
|
110
|
+
plugins_options: plugins_options)
|
111
|
+
else
|
112
|
+
define_restricted_command_method(type, view, mapper: mapper, use: use,
|
113
|
+
plugins_options: plugins_options)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
else
|
117
|
+
@commands ||= []
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# @api public
|
122
|
+
def use(plugin, **options)
|
123
|
+
ROM.plugins[:repository].fetch(plugin).apply_to(self, **options)
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
# @api private
|
129
|
+
def define_command_method(type, **opts)
|
130
|
+
define_method(type) do |*input|
|
131
|
+
if input.size == 1 && input[0].respond_to?(:commit)
|
132
|
+
input[0].commit
|
133
|
+
else
|
134
|
+
root.command(type, **opts).call(*input)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# @api private
|
140
|
+
def define_restricted_command_method(type, views, **opts)
|
141
|
+
views.each do |view_name|
|
142
|
+
meth_name = views.size > 1 ? :"#{type}_#{view_name}" : type
|
143
|
+
|
144
|
+
define_method(meth_name) do |*args|
|
145
|
+
arity = root.__send__(view_name).arity
|
146
|
+
|
147
|
+
view_args = args[0..arity - 1]
|
148
|
+
input = args[arity..args.size - 1]
|
149
|
+
|
150
|
+
changeset = input.first
|
151
|
+
|
152
|
+
if changeset.respond_to?(:commit)
|
153
|
+
changeset.commit
|
154
|
+
else
|
155
|
+
root.public_send(view_name, *view_args).command(type, **opts).(*input)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
class Repository
|
5
|
+
# @api private
|
6
|
+
class RelationReader < Module
|
7
|
+
# @api private
|
8
|
+
attr_reader :klass
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
attr_reader :relations
|
12
|
+
|
13
|
+
module InstanceMethods
|
14
|
+
# @api private
|
15
|
+
def set_relation(name)
|
16
|
+
container
|
17
|
+
.relations[name]
|
18
|
+
.with(auto_struct: auto_struct)
|
19
|
+
.struct_namespace(struct_namespace)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
def initialize(klass, relations)
|
25
|
+
@klass = klass
|
26
|
+
@relations = relations
|
27
|
+
define_readers!
|
28
|
+
end
|
29
|
+
|
30
|
+
# @api private
|
31
|
+
def included(klass)
|
32
|
+
super
|
33
|
+
klass.include(InstanceMethods)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# @api private
|
39
|
+
def define_readers!
|
40
|
+
relations.each do |name|
|
41
|
+
define_method(name) do
|
42
|
+
@relations[name] ||= set_relation(name)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/class_attributes"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
class Repository
|
7
|
+
# A specialized repository type dedicated to work with a root relation
|
8
|
+
#
|
9
|
+
# This repository type builds commands and aggregates for its root relation
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# class UserRepo < ROM::Repository[:users]
|
13
|
+
# commands :create, update: :by_pk, delete: :by_pk
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# rom = ROM.setup(:sql, 'sqlite::memory') do |conf|
|
17
|
+
# conf.default.create_table(:users) do
|
18
|
+
# primary_key :id
|
19
|
+
# column :name, String
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# user_repo = UserRepo.new(rom)
|
24
|
+
#
|
25
|
+
# user = user_repo.create(name: "Jane")
|
26
|
+
#
|
27
|
+
# user_repo.update(user.id, name: "Jane Doe")
|
28
|
+
#
|
29
|
+
# user_repo.delete(user.id)
|
30
|
+
#
|
31
|
+
# @api public
|
32
|
+
class Root < Repository
|
33
|
+
# @!method self.root
|
34
|
+
# Get or set repository root relation identifier
|
35
|
+
#
|
36
|
+
# This method is automatically used when you define a class using
|
37
|
+
# MyRepo[:rel_identifier] shortcut
|
38
|
+
#
|
39
|
+
# @overload root
|
40
|
+
# Return root relation identifier
|
41
|
+
# @return [Symbol]
|
42
|
+
#
|
43
|
+
# @overload root(identifier)
|
44
|
+
# Set root relation identifier
|
45
|
+
# @return [Symbol]
|
46
|
+
defines :root
|
47
|
+
|
48
|
+
# @!attribute [r] root
|
49
|
+
# @return [Relation] The root relation
|
50
|
+
attr_reader :root
|
51
|
+
|
52
|
+
# Sets descendant root relation
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
def self.inherited(klass)
|
56
|
+
super
|
57
|
+
klass.root(root)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @see Repository#initialize
|
61
|
+
def initialize(*)
|
62
|
+
super
|
63
|
+
@root = set_relation(self.class.root)
|
64
|
+
end
|
65
|
+
ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
|
66
|
+
|
67
|
+
# @see ROM::Repository#transaction
|
68
|
+
#
|
69
|
+
# @api public
|
70
|
+
def transaction(gateway: root.gateway, **opts, &block)
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
# TODO: finish this in 1.1.0
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class Session
|
10
|
+
include Dry::Equalizer(:queue, :status)
|
11
|
+
|
12
|
+
attr_reader :repo
|
13
|
+
|
14
|
+
attr_reader :queue
|
15
|
+
|
16
|
+
attr_reader :status
|
17
|
+
|
18
|
+
def initialize(repo)
|
19
|
+
@repo = repo
|
20
|
+
@status = :pending
|
21
|
+
initialize_queue!
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(changeset)
|
25
|
+
queue << changeset
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def commit!
|
30
|
+
queue.each(&:commit)
|
31
|
+
|
32
|
+
@status = :success
|
33
|
+
|
34
|
+
self
|
35
|
+
rescue StandardError => e
|
36
|
+
@status = :failure
|
37
|
+
raise e
|
38
|
+
ensure
|
39
|
+
initialize_queue!
|
40
|
+
end
|
41
|
+
|
42
|
+
def pending?
|
43
|
+
status.equal?(:pending)
|
44
|
+
end
|
45
|
+
|
46
|
+
def success?
|
47
|
+
status.equal?(:success)
|
48
|
+
end
|
49
|
+
|
50
|
+
def failure?
|
51
|
+
status.equal?(:failure)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def initialize_queue!
|
57
|
+
@queue = []
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/cache"
|
4
|
+
require "dry/core/class_attributes"
|
5
|
+
|
6
|
+
require "rom/initializer"
|
7
|
+
require "rom/plugins"
|
8
|
+
require "rom/struct"
|
9
|
+
require "rom/container"
|
10
|
+
require "rom/repository/class_interface"
|
11
|
+
require "rom/repository/session"
|
12
|
+
|
13
|
+
module ROM
|
14
|
+
# Abstract repository class to inherit from
|
15
|
+
#
|
16
|
+
# A repository provides access to composable relations and commands.
|
17
|
+
# Its job is to provide application-specific data that is already materialized, so that
|
18
|
+
# relations don't leak into your application layer.
|
19
|
+
#
|
20
|
+
# Typically, you're going to work with Repository::Root that is configured to
|
21
|
+
# use a single relation as its root, and compose aggregates and use changesets and commands
|
22
|
+
# against the root relation.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# rom = ROM.setup(:sql, 'sqlite::memory') do |conf|
|
26
|
+
# conf.default.create_table(:users) do
|
27
|
+
# primary_key :id
|
28
|
+
# column :name, String
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# conf.default.create_table(:tasks) do
|
32
|
+
# primary_key :id
|
33
|
+
# column :user_id, Integer
|
34
|
+
# column :title, String
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# conf.relation(:users) do
|
38
|
+
# associations do
|
39
|
+
# has_many :tasks
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# class UserRepo < ROM::Repository[:users]
|
45
|
+
# def users_with_tasks
|
46
|
+
# aggregate(:tasks).to_a
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# user_repo = UserRepo.new(rom)
|
51
|
+
# user_repo.users_with_tasks
|
52
|
+
#
|
53
|
+
# @see Repository::Root
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
class Repository
|
57
|
+
extend Dry::Core::Cache
|
58
|
+
extend Dry::Core::ClassAttributes
|
59
|
+
|
60
|
+
extend ClassInterface
|
61
|
+
extend Initializer
|
62
|
+
|
63
|
+
# @!method self.auto_struct
|
64
|
+
# Get or set auto_struct setting
|
65
|
+
#
|
66
|
+
# When disabled, rom structs won't be created
|
67
|
+
#
|
68
|
+
# @overload auto_struct
|
69
|
+
# Return auto_struct setting value
|
70
|
+
# @return [TrueClass,FalseClass]
|
71
|
+
#
|
72
|
+
# @overload auto_struct(value)
|
73
|
+
# Set auto_struct value
|
74
|
+
# @return [Class]
|
75
|
+
defines :auto_struct
|
76
|
+
|
77
|
+
auto_struct true
|
78
|
+
|
79
|
+
# @!method self.auto_struct
|
80
|
+
# Get or set struct namespace
|
81
|
+
defines :struct_namespace
|
82
|
+
|
83
|
+
# @!method self.relation_reader
|
84
|
+
# Get or set relation reader module
|
85
|
+
# @return [RelationReader]
|
86
|
+
defines :relation_reader
|
87
|
+
|
88
|
+
struct_namespace ROM::Struct
|
89
|
+
|
90
|
+
# @!attribute [r] container
|
91
|
+
# @return [ROM::Container] The container used to set up a repo
|
92
|
+
option :container, allow: ROM::Container
|
93
|
+
|
94
|
+
# @!attribute [r] struct_namespace
|
95
|
+
# @return [Module,Class] The namespace for auto-generated structs
|
96
|
+
option :struct_namespace, default: -> { self.class.struct_namespace }
|
97
|
+
|
98
|
+
# @!attribute [r] auto_struct
|
99
|
+
# @return [Boolean] The container used to set up a repo
|
100
|
+
option :auto_struct, default: -> { self.class.auto_struct }
|
101
|
+
|
102
|
+
# @!attribute [r] relations
|
103
|
+
# @return [RelationRegistry] The relation proxy registry used by a repo
|
104
|
+
attr_reader :relations
|
105
|
+
|
106
|
+
# Initializes a new repository object
|
107
|
+
#
|
108
|
+
# @api private
|
109
|
+
def initialize(*)
|
110
|
+
super
|
111
|
+
@relations = {}
|
112
|
+
end
|
113
|
+
ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
|
114
|
+
|
115
|
+
# Open a database transaction
|
116
|
+
# @option gateway [Symbol] gateway key. For Repository::Root descendants
|
117
|
+
# it's taken from the root relation
|
118
|
+
#
|
119
|
+
# @example commited transaction
|
120
|
+
# user = transaction do |t|
|
121
|
+
# create(changeset(name: 'Jane'))
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# user
|
125
|
+
# # => #<ROM::Struct::User id=1 name="Jane">
|
126
|
+
#
|
127
|
+
# @example with a rollback
|
128
|
+
# user = transaction do |t|
|
129
|
+
# changeset(name: 'Jane').commit
|
130
|
+
# t.rollback!
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# user
|
134
|
+
# # nil
|
135
|
+
#
|
136
|
+
# @example with automatic savepoints
|
137
|
+
# user = transaction(auto_savepoint: true) do
|
138
|
+
# create(changeset(name: 'Jane'))
|
139
|
+
#
|
140
|
+
# transaction do |t|
|
141
|
+
# update(changeset(name: 'John'))
|
142
|
+
# t.rollback!
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# user
|
147
|
+
# # => #<ROM::Struct::User id=1 name="Jane">
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
def transaction(gateway: :default, **opts, &block)
|
151
|
+
container.gateways[gateway].transaction(**opts, &block)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Return a string representation of a repository object
|
155
|
+
#
|
156
|
+
# @return [String]
|
157
|
+
#
|
158
|
+
# @api public
|
159
|
+
def inspect
|
160
|
+
%(#<#{self.class} struct_namespace=#{struct_namespace} auto_struct=#{auto_struct}>)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Start a session for multiple changesets
|
164
|
+
#
|
165
|
+
# TODO: this is partly done, needs tweaks in changesets so that we can gather
|
166
|
+
# command results and return them in a nice way
|
167
|
+
#
|
168
|
+
# @!visibility private
|
169
|
+
#
|
170
|
+
# @api public
|
171
|
+
def session
|
172
|
+
session = Session.new(self)
|
173
|
+
yield(session)
|
174
|
+
transaction { session.commit! }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
require "rom/repository/root"
|