rom-repository 1.4.0 → 2.0.0.beta1
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 +14 -6
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +18 -1
- data/lib/rom-repository.rb +1 -2
- data/lib/rom/repository.rb +9 -216
- data/lib/rom/repository/class_interface.rb +16 -33
- data/lib/rom/repository/relation_reader.rb +46 -0
- data/lib/rom/repository/root.rb +3 -59
- data/lib/rom/repository/version.rb +1 -1
- metadata +9 -98
- data/.gitignore +0 -3
- data/.rspec +0 -3
- data/.travis.yml +0 -27
- data/.yardopts +0 -2
- data/Gemfile +0 -38
- data/Rakefile +0 -19
- data/lib/rom/open_struct.rb +0 -35
- data/lib/rom/repository/changeset.rb +0 -155
- data/lib/rom/repository/changeset/associated.rb +0 -100
- data/lib/rom/repository/changeset/create.rb +0 -16
- data/lib/rom/repository/changeset/delete.rb +0 -17
- data/lib/rom/repository/changeset/pipe.rb +0 -97
- data/lib/rom/repository/changeset/restricted.rb +0 -28
- data/lib/rom/repository/changeset/stateful.rb +0 -282
- data/lib/rom/repository/changeset/update.rb +0 -82
- data/lib/rom/repository/command_compiler.rb +0 -257
- data/lib/rom/repository/command_proxy.rb +0 -26
- data/lib/rom/repository/header_builder.rb +0 -65
- data/lib/rom/repository/mapper_builder.rb +0 -23
- data/lib/rom/repository/relation_proxy.rb +0 -337
- data/lib/rom/repository/relation_proxy/combine.rb +0 -320
- data/lib/rom/repository/relation_proxy/wrap.rb +0 -78
- data/lib/rom/repository/struct_builder.rb +0 -83
- data/lib/rom/struct.rb +0 -113
- data/log/.gitkeep +0 -0
- data/rom-repository.gemspec +0 -23
- data/spec/integration/changeset_spec.rb +0 -193
- data/spec/integration/command_macros_spec.rb +0 -191
- data/spec/integration/command_spec.rb +0 -228
- data/spec/integration/multi_adapter_spec.rb +0 -73
- data/spec/integration/repository/aggregate_spec.rb +0 -58
- data/spec/integration/repository_spec.rb +0 -406
- data/spec/integration/root_repository_spec.rb +0 -106
- data/spec/integration/typed_structs_spec.rb +0 -64
- data/spec/shared/database.rb +0 -79
- data/spec/shared/mappers.rb +0 -35
- data/spec/shared/models.rb +0 -41
- data/spec/shared/plugins.rb +0 -66
- data/spec/shared/relations.rb +0 -115
- data/spec/shared/repo.rb +0 -86
- data/spec/shared/seeds.rb +0 -30
- data/spec/shared/structs.rb +0 -140
- data/spec/spec_helper.rb +0 -83
- data/spec/support/mapper_registry.rb +0 -9
- data/spec/support/mutant.rb +0 -10
- data/spec/unit/changeset/associate_spec.rb +0 -120
- data/spec/unit/changeset/map_spec.rb +0 -111
- data/spec/unit/changeset_spec.rb +0 -186
- data/spec/unit/relation_proxy_spec.rb +0 -202
- data/spec/unit/repository/changeset_spec.rb +0 -197
- data/spec/unit/repository/inspect_spec.rb +0 -18
- data/spec/unit/repository/session_spec.rb +0 -251
- data/spec/unit/repository/transaction_spec.rb +0 -42
- data/spec/unit/session_spec.rb +0 -46
- data/spec/unit/struct_builder_spec.rb +0 -128
@@ -1,78 +0,0 @@
|
|
1
|
-
module ROM
|
2
|
-
class Repository
|
3
|
-
class RelationProxy
|
4
|
-
# Provides convenient methods for producing wrapped relations
|
5
|
-
#
|
6
|
-
# @api public
|
7
|
-
module Wrap
|
8
|
-
# Wrap other relations
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# tasks.wrap(owner: [users, user_id: :id])
|
12
|
-
#
|
13
|
-
# @param [Hash] options
|
14
|
-
#
|
15
|
-
# @return [RelationProxy]
|
16
|
-
#
|
17
|
-
# @api public
|
18
|
-
def wrap(*names, **options)
|
19
|
-
new_wraps = wraps_from_names(names) + wraps_from_options(options)
|
20
|
-
|
21
|
-
relation = new_wraps.reduce(self) { |a, e|
|
22
|
-
name = e.meta[:wrap_from_assoc] ? e.meta[:combine_name] : e.base_name.relation
|
23
|
-
a.relation.for_wrap(e.meta.fetch(:keys), name)
|
24
|
-
}
|
25
|
-
|
26
|
-
__new__(relation, meta: { wraps: wraps + new_wraps })
|
27
|
-
end
|
28
|
-
|
29
|
-
# Shortcut to wrap parents
|
30
|
-
#
|
31
|
-
# @example
|
32
|
-
# tasks.wrap_parent(owner: users)
|
33
|
-
#
|
34
|
-
# @return [RelationProxy]
|
35
|
-
#
|
36
|
-
# @api public
|
37
|
-
def wrap_parent(options)
|
38
|
-
wrap(
|
39
|
-
options.each_with_object({}) { |(name, parent), h|
|
40
|
-
keys = combine_keys(parent, relation, :children)
|
41
|
-
h[name] = [parent, keys]
|
42
|
-
}
|
43
|
-
)
|
44
|
-
end
|
45
|
-
|
46
|
-
# Return a wrapped representation of a loading-proxy relation
|
47
|
-
#
|
48
|
-
# This will carry meta info used to produce a correct AST from a relation
|
49
|
-
# so that correct mapper can be generated
|
50
|
-
#
|
51
|
-
# @return [RelationProxy]
|
52
|
-
#
|
53
|
-
# @api private
|
54
|
-
def wrapped(name, keys, wrap_from_assoc = false)
|
55
|
-
with(
|
56
|
-
name: name,
|
57
|
-
meta: {
|
58
|
-
keys: keys, wrap_from_assoc: wrap_from_assoc, wrap: true, combine_name: name
|
59
|
-
}
|
60
|
-
)
|
61
|
-
end
|
62
|
-
|
63
|
-
# @api private
|
64
|
-
def wraps_from_options(options)
|
65
|
-
options.map { |(name, (relation, keys))| relation.wrapped(name, keys) }
|
66
|
-
end
|
67
|
-
|
68
|
-
# @api private
|
69
|
-
def wraps_from_names(names)
|
70
|
-
names.map { |name|
|
71
|
-
assoc = associations[name]
|
72
|
-
registry[assoc.target.relation].wrapped(name, assoc.combine_keys(__registry__), true)
|
73
|
-
}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'dry/core/inflector'
|
2
|
-
require 'dry/core/cache'
|
3
|
-
require 'dry/core/class_builder'
|
4
|
-
|
5
|
-
require 'rom/struct'
|
6
|
-
require 'rom/open_struct'
|
7
|
-
require 'rom/schema/attribute'
|
8
|
-
|
9
|
-
module ROM
|
10
|
-
class Repository
|
11
|
-
# @api private
|
12
|
-
class StructBuilder
|
13
|
-
extend Dry::Core::Cache
|
14
|
-
|
15
|
-
def call(*args)
|
16
|
-
fetch_or_store(*args) do
|
17
|
-
name, header = args
|
18
|
-
attributes = visit(header).compact
|
19
|
-
|
20
|
-
if attributes.empty?
|
21
|
-
ROM::OpenStruct
|
22
|
-
else
|
23
|
-
build_class(name, ROM::Struct) do |klass|
|
24
|
-
attributes.each do |(name, type)|
|
25
|
-
klass.attribute(name, type)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
alias_method :[], :call
|
32
|
-
|
33
|
-
attr_reader :namespace
|
34
|
-
|
35
|
-
def initialize(namespace = nil)
|
36
|
-
@namespace = namespace || ROM::Struct
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def visit(ast)
|
42
|
-
name, node = ast
|
43
|
-
__send__("visit_#{name}", node)
|
44
|
-
end
|
45
|
-
|
46
|
-
def visit_header(node)
|
47
|
-
node.map(&method(:visit))
|
48
|
-
end
|
49
|
-
|
50
|
-
def visit_relation(node)
|
51
|
-
relation_name, meta, header = node
|
52
|
-
name = meta[:combine_name] || relation_name.relation
|
53
|
-
|
54
|
-
model = meta.fetch(:model) { call(name, header) }
|
55
|
-
|
56
|
-
member =
|
57
|
-
if model < Dry::Struct
|
58
|
-
model
|
59
|
-
else
|
60
|
-
Dry::Types::Definition.new(model).constructor(&model.method(:new))
|
61
|
-
end
|
62
|
-
|
63
|
-
if meta[:combine_type] == :many
|
64
|
-
[name, Types::Array.member(member)]
|
65
|
-
else
|
66
|
-
[name, member.optional]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def visit_attribute(attr)
|
71
|
-
[attr.aliased? && !attr.wrapped? ? attr.alias : attr.name, attr.to_read_type]
|
72
|
-
end
|
73
|
-
|
74
|
-
def build_class(name, parent, &block)
|
75
|
-
Dry::Core::ClassBuilder.new(name: class_name(name), parent: parent, namespace: namespace).call(&block)
|
76
|
-
end
|
77
|
-
|
78
|
-
def class_name(name)
|
79
|
-
Dry::Core::Inflector.classify(Dry::Core::Inflector.singularize(name))
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
data/lib/rom/struct.rb
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
require 'dry/struct'
|
2
|
-
|
3
|
-
module ROM
|
4
|
-
# Simple data-struct class
|
5
|
-
#
|
6
|
-
# ROM structs are plain data structures loaded by repositories.
|
7
|
-
# They implement Hash protocol which means that they can be used
|
8
|
-
# in places where Hash-like objects are supported.
|
9
|
-
#
|
10
|
-
# Repositories define subclasses of ROM::Struct automatically, they are
|
11
|
-
# defined in the ROM::Struct namespace by default, but you set it up
|
12
|
-
# to use your namespace/module as well.
|
13
|
-
#
|
14
|
-
# Structs are based on dry-struct gem, they include `schema` with detailed information
|
15
|
-
# about attribute types returned from relations, thus can be introspected to build
|
16
|
-
# additional functionality when desired.
|
17
|
-
#
|
18
|
-
# There is a caveat you should know about when working with structs. Struct classes
|
19
|
-
# have names but at the same time they're anonymous, i.e. you can't get the User struct class
|
20
|
-
# with ROM::Struct::User. ROM will create as many struct classes for User as needed,
|
21
|
-
# they all will have the same name and ROM::Struct::User will be the common parent class for
|
22
|
-
# them. Combined with the ability to provide your own namespace for structs this enables to
|
23
|
-
# pre-define the parent class.
|
24
|
-
#
|
25
|
-
# @example accessing relation struct model
|
26
|
-
# rom = ROM.container(:sql, 'sqlite::memory') do |conf|
|
27
|
-
# conf.default.create_table(:users) do
|
28
|
-
# primary_key :id
|
29
|
-
# column :name, String
|
30
|
-
# end
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# class UserRepo < ROM::Repository[:users]
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# user_repo = UserRepo.new(rom)
|
37
|
-
#
|
38
|
-
# # get auto-generated User struct
|
39
|
-
# model = user_repo.users.mapper.model
|
40
|
-
# # => ROM::Struct::User
|
41
|
-
#
|
42
|
-
# # see struct's schema attributes
|
43
|
-
#
|
44
|
-
# # model.schema[:id]
|
45
|
-
# # => #<Dry::Types::Constrained type=#<Dry::Types::Definition primitive=Integer options={}> options={:rule=>#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#gt?> options={:args=>[0]}>, :meta=>{:primary_key=>true, :name=>:id, :source=>ROM::Relation::Name(users)}} rule=#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#gt?> options={:args=>[0]}>>
|
46
|
-
#
|
47
|
-
# model.schema[:name]
|
48
|
-
# # => #<Dry::Types::Sum left=#<Dry::Types::Constrained type=#<Dry::Types::Definition primitive=NilClass options={}> options={:rule=>#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#type?> options={:args=>[NilClass]}>} rule=#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#type?> options={:args=>[NilClass]}>> right=#<Dry::Types::Definition primitive=String options={}> options={:meta=>{:name=>:name, :source=>ROM::Relation::Name(users)}}>
|
49
|
-
#
|
50
|
-
# @example passing a namespace with an existing parent class
|
51
|
-
# module Entities
|
52
|
-
# class User < ROM::Struct
|
53
|
-
# def upcased_name
|
54
|
-
# name.upcase
|
55
|
-
# end
|
56
|
-
# end
|
57
|
-
# end
|
58
|
-
#
|
59
|
-
# class UserRepo < ROM::Repository[:users]
|
60
|
-
# struct_namespace Entities
|
61
|
-
# end
|
62
|
-
#
|
63
|
-
# user_repo = UserRepo.new(rom)
|
64
|
-
# user = user_repo.users.by_pk(1).one!
|
65
|
-
# user.name # => "Jane"
|
66
|
-
# user.upcased_name # => "JANE"
|
67
|
-
#
|
68
|
-
# @see http://dry-rb.org/gems/dry-struct dry-struct
|
69
|
-
# @see http://dry-rb.org/gems/dry-types dry-types
|
70
|
-
#
|
71
|
-
# @api public
|
72
|
-
class Struct < Dry::Struct
|
73
|
-
MissingAttribute = Class.new(NameError)
|
74
|
-
|
75
|
-
# Returns a short string representation
|
76
|
-
#
|
77
|
-
# @return [String]
|
78
|
-
#
|
79
|
-
# @api public
|
80
|
-
def to_s
|
81
|
-
"#<#{self.class}:0x#{(object_id << 1).to_s(16)}>"
|
82
|
-
end
|
83
|
-
|
84
|
-
# Return attribute value
|
85
|
-
#
|
86
|
-
# @param [Symbol] name The attribute name
|
87
|
-
#
|
88
|
-
# @api public
|
89
|
-
def fetch(name)
|
90
|
-
__send__(name)
|
91
|
-
end
|
92
|
-
|
93
|
-
if RUBY_VERSION < '2.3'
|
94
|
-
# @api private
|
95
|
-
def respond_to?(*)
|
96
|
-
super
|
97
|
-
end
|
98
|
-
else
|
99
|
-
# @api private
|
100
|
-
def respond_to_missing?(*)
|
101
|
-
super
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
private
|
106
|
-
|
107
|
-
def method_missing(method, *)
|
108
|
-
super
|
109
|
-
rescue NameError => error
|
110
|
-
raise MissingAttribute.new("#{ error.message } (not loaded attribute?)")
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
data/log/.gitkeep
DELETED
File without changes
|
data/rom-repository.gemspec
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require File.expand_path('../lib/rom/repository/version', __FILE__)
|
2
|
-
|
3
|
-
Gem::Specification.new do |gem|
|
4
|
-
gem.name = 'rom-repository'
|
5
|
-
gem.summary = 'Repository abstraction for rom-rb'
|
6
|
-
gem.description = 'rom-repository adds support for auto-mapping and commands on top of rom-rb relations'
|
7
|
-
gem.author = 'Piotr Solnica'
|
8
|
-
gem.email = 'piotr.solnica+oss@gmail.com'
|
9
|
-
gem.homepage = 'http://rom-rb.org'
|
10
|
-
gem.require_paths = ['lib']
|
11
|
-
gem.version = ROM::Repository::VERSION.dup
|
12
|
-
gem.files = `git ls-files`.split("\n").reject { |name| name.include?('benchmarks') || name.include?('examples') || name.include?('bin/console') }
|
13
|
-
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
14
|
-
gem.license = 'MIT'
|
15
|
-
|
16
|
-
gem.add_runtime_dependency 'rom', '~> 3.3'
|
17
|
-
gem.add_runtime_dependency 'rom-mapper', '~> 0.5'
|
18
|
-
gem.add_runtime_dependency 'dry-core', '~> 0.3', '>= 0.3.1'
|
19
|
-
gem.add_runtime_dependency 'dry-struct', '~> 0.3'
|
20
|
-
|
21
|
-
gem.add_development_dependency 'rake', '~> 11.2'
|
22
|
-
gem.add_development_dependency 'rspec', '~> 3.5'
|
23
|
-
end
|
@@ -1,193 +0,0 @@
|
|
1
|
-
RSpec.describe 'Using changesets' do
|
2
|
-
include_context 'database'
|
3
|
-
include_context 'relations'
|
4
|
-
|
5
|
-
before do
|
6
|
-
module Test
|
7
|
-
class User < Dry::Struct
|
8
|
-
attribute :id, Dry::Types['strict.int']
|
9
|
-
attribute :name, Dry::Types['strict.string']
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
configuration.mappers do
|
14
|
-
define(:users) do
|
15
|
-
model Test::User
|
16
|
-
register_as :user
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe 'Create' do
|
22
|
-
subject(:repo) do
|
23
|
-
Class.new(ROM::Repository[:users]) {
|
24
|
-
relations :books, :posts
|
25
|
-
commands :create, update: :by_pk
|
26
|
-
}.new(rom)
|
27
|
-
end
|
28
|
-
|
29
|
-
let(:create_changeset) do
|
30
|
-
Class.new(ROM::Changeset::Create)
|
31
|
-
end
|
32
|
-
|
33
|
-
let(:add_book_changeset) do
|
34
|
-
Class.new(ROM::Changeset::Create[:books])
|
35
|
-
end
|
36
|
-
|
37
|
-
let(:update_changeset) do
|
38
|
-
Class.new(ROM::Changeset::Update)
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'can be passed to a command' do
|
42
|
-
changeset = repo.changeset(name: "Jane Doe")
|
43
|
-
command = repo.command(:create, repo.users)
|
44
|
-
result = command.(changeset)
|
45
|
-
|
46
|
-
expect(result.id).to_not be(nil)
|
47
|
-
expect(result.name).to eql("Jane Doe")
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'can be passed to a command graph' do
|
51
|
-
changeset = repo.changeset(
|
52
|
-
name: "Jane Doe", posts: [{ title: "Just Do It", alien: "or sutin" }]
|
53
|
-
)
|
54
|
-
|
55
|
-
command = repo.command(:create, repo.aggregate(:posts))
|
56
|
-
result = command.(changeset)
|
57
|
-
|
58
|
-
expect(result.id).to_not be(nil)
|
59
|
-
expect(result.name).to eql("Jane Doe")
|
60
|
-
expect(result.posts.size).to be(1)
|
61
|
-
expect(result.posts[0].title).to eql("Just Do It")
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'preprocesses data using changeset pipes' do
|
65
|
-
changeset = repo.changeset(:books, title: "rom-rb is awesome").map(:add_timestamps)
|
66
|
-
command = repo.command(:create, repo.books)
|
67
|
-
result = command.(changeset)
|
68
|
-
|
69
|
-
expect(result.id).to_not be(nil)
|
70
|
-
expect(result.title).to eql("rom-rb is awesome")
|
71
|
-
expect(result.created_at).to be_instance_of(Time)
|
72
|
-
expect(result.updated_at).to be_instance_of(Time)
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'preprocesses data using custom block' do
|
76
|
-
changeset = repo.
|
77
|
-
changeset(:books, title: "rom-rb is awesome").
|
78
|
-
map { |tuple| tuple.merge(created_at: Time.now) }
|
79
|
-
|
80
|
-
command = repo.command(:create, repo.books)
|
81
|
-
result = command.(changeset)
|
82
|
-
|
83
|
-
expect(result.id).to_not be(nil)
|
84
|
-
expect(result.title).to eql("rom-rb is awesome")
|
85
|
-
expect(result.created_at).to be_instance_of(Time)
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'preprocesses data using built-in steps and custom block' do
|
89
|
-
changeset = repo.
|
90
|
-
changeset(:books, title: "rom-rb is awesome").
|
91
|
-
extend(:touch) { |tuple| tuple.merge(created_at: Time.now) }
|
92
|
-
|
93
|
-
command = repo.command(:create, repo.books)
|
94
|
-
result = command.(changeset)
|
95
|
-
|
96
|
-
expect(result.id).to_not be(nil)
|
97
|
-
expect(result.title).to eql("rom-rb is awesome")
|
98
|
-
expect(result.created_at).to be_instance_of(Time)
|
99
|
-
expect(result.updated_at).to be_instance_of(Time)
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'preserves relation mappers with create' do
|
103
|
-
changeset = repo.
|
104
|
-
changeset(create_changeset).
|
105
|
-
new(repo.users.relation.as(:user)).
|
106
|
-
data(name: 'Joe Dane')
|
107
|
-
|
108
|
-
expect(changeset.commit).to eql(Test::User.new(id: 1, name: 'Joe Dane'))
|
109
|
-
end
|
110
|
-
|
111
|
-
it 'creates changesets for non-root relations' do
|
112
|
-
repo.create(name: 'John Doe')
|
113
|
-
changeset = repo.changeset(add_book_changeset).data(title: 'The War of the Worlds')
|
114
|
-
|
115
|
-
expect(changeset.commit).
|
116
|
-
to include(
|
117
|
-
id: 1,
|
118
|
-
title: 'The War of the Worlds',
|
119
|
-
created_at: nil,
|
120
|
-
updated_at: nil
|
121
|
-
)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
describe 'Update' do
|
126
|
-
subject(:repo) do
|
127
|
-
Class.new(ROM::Repository[:books]) {
|
128
|
-
commands :create, update: :by_pk
|
129
|
-
}.new(rom)
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'can be passed to a command' do
|
133
|
-
book = repo.create(title: 'rom-rb is awesome')
|
134
|
-
|
135
|
-
changeset = repo
|
136
|
-
.changeset(book.id, title: 'rom-rb is awesome for real')
|
137
|
-
.extend(:touch)
|
138
|
-
|
139
|
-
expect(changeset.diff).to eql(title: 'rom-rb is awesome for real')
|
140
|
-
|
141
|
-
result = repo.update(book.id, changeset)
|
142
|
-
|
143
|
-
expect(result.id).to be(book.id)
|
144
|
-
expect(result.title).to eql('rom-rb is awesome for real')
|
145
|
-
expect(result.updated_at).to be_instance_of(Time)
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'skips update execution with no diff' do
|
149
|
-
book = repo.create(title: 'rom-rb is awesome')
|
150
|
-
|
151
|
-
changeset = repo
|
152
|
-
.changeset(book.id, title: 'rom-rb is awesome')
|
153
|
-
.extend(:touch)
|
154
|
-
|
155
|
-
expect(changeset).to_not be_diff
|
156
|
-
|
157
|
-
result = repo.update(book.id, changeset)
|
158
|
-
|
159
|
-
expect(result.id).to be(book.id)
|
160
|
-
expect(result.title).to eql('rom-rb is awesome')
|
161
|
-
expect(result.updated_at).to be(nil)
|
162
|
-
end
|
163
|
-
|
164
|
-
it 'works with mixed several class-level pipes' do
|
165
|
-
book = repo.create(title: 'rom-rb is awesome')
|
166
|
-
|
167
|
-
changeset_class = Class.new(ROM::Changeset::Update[:books]) do
|
168
|
-
map { |title: | { title: title.upcase } }
|
169
|
-
extend { |title: | { title: title.reverse } }
|
170
|
-
end
|
171
|
-
|
172
|
-
changeset = repo
|
173
|
-
.changeset(changeset_class)
|
174
|
-
.by_pk(book.id)
|
175
|
-
.data(title: 'rom-rb is really awesome')
|
176
|
-
|
177
|
-
expect(changeset.diff).to eql(title: 'ROM-RB IS REALLY AWESOME')
|
178
|
-
expect(changeset.to_h).to eql(title: 'EMOSEWA YLLAER SI BR-MOR')
|
179
|
-
end
|
180
|
-
|
181
|
-
it 'works with mixed several instance-level pipes' do
|
182
|
-
book = repo.create(title: 'rom-rb is awesome')
|
183
|
-
|
184
|
-
changeset = repo.
|
185
|
-
changeset(book.id, title: 'rom-rb is really awesome').
|
186
|
-
map { |title: | { title: title.upcase } }.
|
187
|
-
extend { |title: | { title: title.reverse } }
|
188
|
-
|
189
|
-
expect(changeset.diff).to eql(title: 'ROM-RB IS REALLY AWESOME')
|
190
|
-
expect(changeset.to_h).to eql(title: 'EMOSEWA YLLAER SI BR-MOR')
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|