rom-relation 0.1.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.
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +21 -0
- data/.yardopts +4 -0
- data/Gemfile +24 -0
- data/Gemfile.devtools +55 -0
- data/Guardfile +25 -0
- data/LICENSE +20 -0
- data/README.md +21 -0
- data/Rakefile +4 -0
- data/TODO.md +4 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +8 -0
- data/config/reek.yml +97 -0
- data/config/rubocop.yml +41 -0
- data/lib/rom/environment.rb +133 -0
- data/lib/rom/mapping/definition.rb +127 -0
- data/lib/rom/mapping.rb +81 -0
- data/lib/rom/relation.rb +339 -0
- data/lib/rom/repository.rb +62 -0
- data/lib/rom/schema/definition/relation/base.rb +25 -0
- data/lib/rom/schema/definition/relation.rb +44 -0
- data/lib/rom/schema/definition.rb +82 -0
- data/lib/rom/schema.rb +49 -0
- data/lib/rom/support/axiom/adapter/data_objects.rb +39 -0
- data/lib/rom/support/axiom/adapter/memory.rb +25 -0
- data/lib/rom/support/axiom/adapter/postgres.rb +19 -0
- data/lib/rom/support/axiom/adapter/sqlite3.rb +19 -0
- data/lib/rom/support/axiom/adapter.rb +100 -0
- data/lib/rom/version.rb +7 -0
- data/lib/rom-relation.rb +45 -0
- data/rom-relation.gemspec +26 -0
- data/spec/integration/environment_setup_spec.rb +22 -0
- data/spec/integration/mapping_relations_spec.rb +64 -0
- data/spec/integration/schema_definition_spec.rb +94 -0
- data/spec/shared/unit/environment_context.rb +6 -0
- data/spec/shared/unit/relation_context.rb +25 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/helper.rb +17 -0
- data/spec/support/test_mapper.rb +23 -0
- data/spec/unit/rom/environment/class_methods/setup_spec.rb +25 -0
- data/spec/unit/rom/environment/element_reader_spec.rb +23 -0
- data/spec/unit/rom/environment/mapping_spec.rb +26 -0
- data/spec/unit/rom/environment/repository_spec.rb +21 -0
- data/spec/unit/rom/environment/schema_spec.rb +33 -0
- data/spec/unit/rom/mapping/class_methods/build_spec.rb +77 -0
- data/spec/unit/rom/relation/class_methods/build_spec.rb +19 -0
- data/spec/unit/rom/relation/delete_spec.rb +15 -0
- data/spec/unit/rom/relation/drop_spec.rb +11 -0
- data/spec/unit/rom/relation/each_spec.rb +23 -0
- data/spec/unit/rom/relation/first_spec.rb +19 -0
- data/spec/unit/rom/relation/inject_mapper_spec.rb +17 -0
- data/spec/unit/rom/relation/insert_spec.rb +13 -0
- data/spec/unit/rom/relation/last_spec.rb +19 -0
- data/spec/unit/rom/relation/one_spec.rb +49 -0
- data/spec/unit/rom/relation/replace_spec.rb +13 -0
- data/spec/unit/rom/relation/restrict_spec.rb +25 -0
- data/spec/unit/rom/relation/sort_by_spec.rb +25 -0
- data/spec/unit/rom/relation/take_spec.rb +11 -0
- data/spec/unit/rom/relation/to_a_spec.rb +20 -0
- data/spec/unit/rom/relation/update_spec.rb +25 -0
- data/spec/unit/rom/repository/class_methods/build_spec.rb +27 -0
- data/spec/unit/rom/repository/element_reader_spec.rb +21 -0
- data/spec/unit/rom/repository/element_writer_spec.rb +18 -0
- data/spec/unit/rom/schema/class_methods/build_spec.rb +103 -0
- metadata +249 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'axiom-memory-adapter'
|
|
4
|
+
require 'rom/support/axiom/adapter'
|
|
5
|
+
|
|
6
|
+
module Axiom
|
|
7
|
+
module Adapter
|
|
8
|
+
|
|
9
|
+
# A axiom in memory adapter
|
|
10
|
+
#
|
|
11
|
+
# This is basically a "null adapter"
|
|
12
|
+
# as it doesn't make use of it's uri
|
|
13
|
+
# and only passes through the given
|
|
14
|
+
# +relation+ in {#gateway}
|
|
15
|
+
#
|
|
16
|
+
class Memory
|
|
17
|
+
extend Adapter
|
|
18
|
+
|
|
19
|
+
include Equalizer.new(:schema)
|
|
20
|
+
|
|
21
|
+
uri_scheme :memory
|
|
22
|
+
|
|
23
|
+
end # class Memory
|
|
24
|
+
end # module Adapter
|
|
25
|
+
end # module Axiom
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'do_postgres'
|
|
4
|
+
|
|
5
|
+
require 'rom/support/axiom/adapter'
|
|
6
|
+
require 'rom/support/axiom/adapter/data_objects'
|
|
7
|
+
|
|
8
|
+
module Axiom
|
|
9
|
+
module Adapter
|
|
10
|
+
|
|
11
|
+
# A Axiom adapter for postgres
|
|
12
|
+
#
|
|
13
|
+
class Postgres < DataObjects
|
|
14
|
+
|
|
15
|
+
uri_scheme :postgres
|
|
16
|
+
|
|
17
|
+
end # class Postgres
|
|
18
|
+
end # module Adapter
|
|
19
|
+
end # module Axiom
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'do_sqlite3'
|
|
4
|
+
|
|
5
|
+
require 'rom/support/axiom/adapter'
|
|
6
|
+
require 'rom/support/axiom/adapter/data_objects'
|
|
7
|
+
|
|
8
|
+
module Axiom
|
|
9
|
+
module Adapter
|
|
10
|
+
|
|
11
|
+
# A axiom adapter for sqlite3
|
|
12
|
+
#
|
|
13
|
+
class Sqlite3 < DataObjects
|
|
14
|
+
|
|
15
|
+
uri_scheme :sqlite3
|
|
16
|
+
|
|
17
|
+
end # class Sqlite3
|
|
18
|
+
end # module Adapter
|
|
19
|
+
end # module Axiom
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Axiom
|
|
4
|
+
|
|
5
|
+
# Raised when passing an +uri+ with an unregistered scheme to {Adapter.new}
|
|
6
|
+
UnknownAdapterError = Class.new(StandardError)
|
|
7
|
+
|
|
8
|
+
# Provides base functionality for every axiom adapter
|
|
9
|
+
#
|
|
10
|
+
# @todo think about making this a (base) class
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
#
|
|
14
|
+
# class MyAdapter
|
|
15
|
+
# extend Axiom::Adapter
|
|
16
|
+
# uri_scheme :foo
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
module Adapter
|
|
20
|
+
|
|
21
|
+
# The registry of adapters
|
|
22
|
+
#
|
|
23
|
+
# @return [Hash<String, Object>]
|
|
24
|
+
# a hash of adapters, keyed by uri scheme
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
REGISTRY = {}
|
|
28
|
+
|
|
29
|
+
# Return the adapter to use for the given +uri+
|
|
30
|
+
#
|
|
31
|
+
# @param [Addressable::URI] uri
|
|
32
|
+
# the uri to initialize the adapter with
|
|
33
|
+
#
|
|
34
|
+
# @return [Object]
|
|
35
|
+
# a axiom adapter
|
|
36
|
+
#
|
|
37
|
+
# @raise [UnknownAdapterError]
|
|
38
|
+
# when the given +uri+'s scheme is not registered
|
|
39
|
+
#
|
|
40
|
+
# @api private
|
|
41
|
+
def self.build(uri)
|
|
42
|
+
klass = get(uri)
|
|
43
|
+
|
|
44
|
+
if klass.name == 'Axiom::Adapter::Memory'
|
|
45
|
+
klass.new
|
|
46
|
+
else
|
|
47
|
+
klass.new(uri)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Return the adapter class registered for +uri+
|
|
52
|
+
#
|
|
53
|
+
# @param [Addressable::URI] uri
|
|
54
|
+
# the uri that identifies the adapter class
|
|
55
|
+
#
|
|
56
|
+
# @return [Class]
|
|
57
|
+
# a axiom adapter class
|
|
58
|
+
#
|
|
59
|
+
# @raise [UnknownAdapterError]
|
|
60
|
+
# when the given +uri+'s scheme is not registered
|
|
61
|
+
#
|
|
62
|
+
# @api private
|
|
63
|
+
def self.get(uri)
|
|
64
|
+
uri_scheme = uri.scheme
|
|
65
|
+
|
|
66
|
+
REGISTRY.fetch(uri_scheme) {
|
|
67
|
+
raise(
|
|
68
|
+
UnknownAdapterError,
|
|
69
|
+
"#{uri_scheme.inspect} is no registered uri scheme"
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Set the uri scheme for an adapter class
|
|
75
|
+
#
|
|
76
|
+
# @example for a DataObjects adapter
|
|
77
|
+
#
|
|
78
|
+
# class Postgres < Axiom::Adapter::DataObjects
|
|
79
|
+
# uri_scheme :postgres
|
|
80
|
+
# end
|
|
81
|
+
#
|
|
82
|
+
# @example for an arbitrary adapter
|
|
83
|
+
#
|
|
84
|
+
# class InMemory
|
|
85
|
+
# extend Axiom::Adapter
|
|
86
|
+
# uri_scheme :in_memory
|
|
87
|
+
# end
|
|
88
|
+
#
|
|
89
|
+
# @param [#to_s] name
|
|
90
|
+
# the name of the uri scheme
|
|
91
|
+
#
|
|
92
|
+
# @return [self]
|
|
93
|
+
#
|
|
94
|
+
# @api public
|
|
95
|
+
def uri_scheme(name)
|
|
96
|
+
REGISTRY[name.to_s] = self
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end # module Adapter
|
|
100
|
+
end # module Axiom
|
data/lib/rom/version.rb
ADDED
data/lib/rom-relation.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'addressable/uri'
|
|
4
|
+
|
|
5
|
+
require 'set'
|
|
6
|
+
require 'concord'
|
|
7
|
+
require 'abstract_type'
|
|
8
|
+
require 'descendants_tracker'
|
|
9
|
+
require 'equalizer'
|
|
10
|
+
require 'axiom'
|
|
11
|
+
|
|
12
|
+
# Main ROM module with methods to setup and manage the environment
|
|
13
|
+
module ROM
|
|
14
|
+
|
|
15
|
+
# Raised when the returned tuples are unexpectedly empty
|
|
16
|
+
NoTuplesError = Class.new(RuntimeError)
|
|
17
|
+
|
|
18
|
+
# Raised when the returned tuples are unexpectedly too many
|
|
19
|
+
ManyTuplesError = Class.new(RuntimeError)
|
|
20
|
+
|
|
21
|
+
# Represent an undefined argument
|
|
22
|
+
Undefined = Object.new.freeze
|
|
23
|
+
|
|
24
|
+
# An empty frozen Hash useful for parameter default values
|
|
25
|
+
EMPTY_HASH = {}.freeze
|
|
26
|
+
|
|
27
|
+
# An empty frozen Array useful for parameter default values
|
|
28
|
+
EMPTY_ARRAY = [].freeze
|
|
29
|
+
|
|
30
|
+
# Represent a positive, infinitely large Float number
|
|
31
|
+
Infinity = 1.0 / 0
|
|
32
|
+
|
|
33
|
+
end # module ROM
|
|
34
|
+
|
|
35
|
+
require 'rom/repository'
|
|
36
|
+
require 'rom/environment'
|
|
37
|
+
require 'rom/relation'
|
|
38
|
+
|
|
39
|
+
require 'rom/schema'
|
|
40
|
+
require 'rom/schema/definition'
|
|
41
|
+
require 'rom/schema/definition/relation'
|
|
42
|
+
require 'rom/schema/definition/relation/base'
|
|
43
|
+
|
|
44
|
+
require 'rom/mapping'
|
|
45
|
+
require 'rom/mapping/definition'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.expand_path('../lib/rom/version', __FILE__)
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |gem|
|
|
6
|
+
gem.name = 'rom-relation'
|
|
7
|
+
gem.summary = 'Relation schema with mapping for ROM'
|
|
8
|
+
gem.description = gem.summary
|
|
9
|
+
gem.authors = 'Piotr Solnica'
|
|
10
|
+
gem.email = 'piotr.solnica@gmail.com'
|
|
11
|
+
gem.homepage = 'http://rom-rb.org'
|
|
12
|
+
gem.require_paths = ['lib']
|
|
13
|
+
gem.version = ROM::Relation::VERSION
|
|
14
|
+
gem.files = `git ls-files`.split("\n")
|
|
15
|
+
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
|
16
|
+
gem.license = 'MIT'
|
|
17
|
+
|
|
18
|
+
gem.add_dependency 'addressable', '~> 2.3', '>= 2.3.3'
|
|
19
|
+
gem.add_dependency 'concord', '~> 0.1.4'
|
|
20
|
+
gem.add_dependency 'equalizer', '~> 0.0.7'
|
|
21
|
+
gem.add_dependency 'descendants_tracker', '~> 0.0.1'
|
|
22
|
+
gem.add_dependency 'abstract_type', '~> 0.0.6'
|
|
23
|
+
gem.add_dependency 'adamantium', '~> 0.1'
|
|
24
|
+
gem.add_dependency 'axiom', '~> 0.1.1'
|
|
25
|
+
gem.add_dependency 'axiom-optimizer', '~> 0.1.0'
|
|
26
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'Setting up environment' do
|
|
6
|
+
it 'registers relations within repositories' do
|
|
7
|
+
env = ROM::Environment.setup(memory: 'memory://test')
|
|
8
|
+
|
|
9
|
+
schema = env.schema do
|
|
10
|
+
base_relation :users do
|
|
11
|
+
repository :memory
|
|
12
|
+
|
|
13
|
+
attribute :id, Integer
|
|
14
|
+
attribute :name, String
|
|
15
|
+
|
|
16
|
+
key :id
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
expect(schema[:users]).to be_instance_of(Axiom::Relation::Variable)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'Defining relation mappings' do
|
|
6
|
+
let!(:schema) {
|
|
7
|
+
env.schema {
|
|
8
|
+
base_relation :users do
|
|
9
|
+
repository :test
|
|
10
|
+
|
|
11
|
+
attribute :id, Integer
|
|
12
|
+
attribute :user_name, String
|
|
13
|
+
|
|
14
|
+
key :id
|
|
15
|
+
end
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let!(:env) {
|
|
20
|
+
Environment.setup(test: 'memory://test')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
before do
|
|
24
|
+
User = mock_model(:id, :name)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
after do
|
|
28
|
+
Object.send(:remove_const, :User)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
specify 'building registry of automatically mapped relations' do
|
|
32
|
+
env.mapping do
|
|
33
|
+
users do
|
|
34
|
+
model User
|
|
35
|
+
|
|
36
|
+
map :id
|
|
37
|
+
map :user_name, to: :name
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
users = env[:users]
|
|
42
|
+
|
|
43
|
+
jane = User.new(id: 1, name: 'Jane')
|
|
44
|
+
|
|
45
|
+
users.insert(jane)
|
|
46
|
+
|
|
47
|
+
expect(users.to_a).to eql([jane])
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
specify 'providing custom mapper' do
|
|
51
|
+
custom_model = mock_model(:id, :user_name)
|
|
52
|
+
custom_mapper = TestMapper.new(schema[:users].header, custom_model)
|
|
53
|
+
|
|
54
|
+
env.mapping { users { mapper(custom_mapper) } }
|
|
55
|
+
|
|
56
|
+
users = env[:users]
|
|
57
|
+
|
|
58
|
+
jane = custom_model.new(id: 1, user_name: 'Jane')
|
|
59
|
+
|
|
60
|
+
users.insert(jane)
|
|
61
|
+
|
|
62
|
+
expect(users.to_a).to eql([jane])
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'Defining a ROM schema' do
|
|
6
|
+
let(:people) {
|
|
7
|
+
Axiom::Relation::Base.new(:people, people_header)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let(:people_header) {
|
|
11
|
+
Axiom::Relation::Header.coerce(people_attributes, keys: people_keys)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let(:people_attributes) {
|
|
15
|
+
[[:id, Integer], [:name, String]]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let(:people_keys) {
|
|
19
|
+
[:id]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let(:profiles) {
|
|
23
|
+
Axiom::Relation::Base.new(:profiles, profiles_header)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let(:profiles_header) {
|
|
27
|
+
Axiom::Relation::Header.coerce(profiles_attributes, keys: profiles_keys)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let(:profiles_attributes) {
|
|
31
|
+
[[:id, Integer], [:person_id, Integer], [:text, String]]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let(:profiles_keys) {
|
|
35
|
+
[:id, :person_id]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let(:people_with_profile) {
|
|
39
|
+
people.join(profiles.rename(id: :profile_id, person_id: :id))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let(:env) { Environment.setup(test: 'memory://test') }
|
|
43
|
+
let(:repository) { env.repository(:test) }
|
|
44
|
+
|
|
45
|
+
let(:schema) do
|
|
46
|
+
env.schema do
|
|
47
|
+
base_relation :people do
|
|
48
|
+
repository :test
|
|
49
|
+
|
|
50
|
+
attribute :id, Integer
|
|
51
|
+
attribute :name, String
|
|
52
|
+
|
|
53
|
+
key :id
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
base_relation :profiles do
|
|
57
|
+
repository :test
|
|
58
|
+
|
|
59
|
+
attribute :id, Integer
|
|
60
|
+
attribute :person_id, Integer
|
|
61
|
+
attribute :text, String
|
|
62
|
+
|
|
63
|
+
key :id
|
|
64
|
+
key :person_id
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
env.schema do
|
|
69
|
+
relation :people_with_profile do
|
|
70
|
+
people.join(profiles.rename(id: :profile_id, person_id: :id))
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'registers the people relation' do
|
|
76
|
+
expect(schema[:people]).to eq(people)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'establishes key attributes for people relation' do
|
|
80
|
+
expect(schema[:people].header.keys).to include(*people_keys)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'establishes key attributes for profiles relation' do
|
|
84
|
+
expect(schema[:profiles].header.keys).to include(*profiles_keys)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'registers the profiles relation' do
|
|
88
|
+
expect(schema[:profiles]).to eq(profiles)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'registers the people_with_profile relation' do
|
|
92
|
+
expect(schema[:people_with_profile]).to eq(people_with_profile)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# # encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# encoding: utf-8
|
|
4
|
+
|
|
5
|
+
shared_context 'Relation' do
|
|
6
|
+
subject(:relation) { described_class.new(users, mapper) }
|
|
7
|
+
|
|
8
|
+
let(:header) {
|
|
9
|
+
Axiom::Relation::Header.coerce([[:id, Integer], [:name, String]], keys: [:id])
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let(:users) {
|
|
13
|
+
Axiom::Relation.new(header, [
|
|
14
|
+
[1, 'John'], [2, 'Jane'], [3, 'Jack'], [4, 'Jade']
|
|
15
|
+
])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let(:model) { mock_model(:id, :name) }
|
|
19
|
+
let(:mapper) { TestMapper.new(users.header, model) }
|
|
20
|
+
|
|
21
|
+
let(:john) { model.new(id: 1, name: 'John') }
|
|
22
|
+
let(:jane) { model.new(id: 2, name: 'Jane') }
|
|
23
|
+
let(:jack) { model.new(id: 3, name: 'Jack') }
|
|
24
|
+
let(:jade) { model.new(id: 4, name: 'Jade') }
|
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# SimpleCov MUST be started before require 'rom-relation'
|
|
4
|
+
#
|
|
5
|
+
if ENV['COVERAGE'] == 'true'
|
|
6
|
+
require 'simplecov'
|
|
7
|
+
require 'coveralls'
|
|
8
|
+
|
|
9
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
|
10
|
+
SimpleCov::Formatter::HTMLFormatter,
|
|
11
|
+
Coveralls::SimpleCov::Formatter
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
SimpleCov.start do
|
|
15
|
+
command_name 'spec:unit'
|
|
16
|
+
|
|
17
|
+
add_filter 'config'
|
|
18
|
+
add_filter 'lib/rom/support'
|
|
19
|
+
add_filter 'spec'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require 'rom-relation'
|
|
24
|
+
require 'rom-mapper'
|
|
25
|
+
require 'rom/support/axiom/adapter/memory'
|
|
26
|
+
|
|
27
|
+
require 'devtools/spec_helper'
|
|
28
|
+
require 'bogus/rspec'
|
|
29
|
+
|
|
30
|
+
include ROM
|
|
31
|
+
|
|
32
|
+
ROM_ENV = Environment.setup(test: 'memory://test')
|
|
33
|
+
ROM_ADAPTER = ENV.fetch('ROM_ADAPTER', :in_memory).to_sym
|
|
34
|
+
|
|
35
|
+
Bogus.configure do |config|
|
|
36
|
+
config.search_modules << ROM
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
RSpec.configure do |config|
|
|
40
|
+
config.include(SpecHelper)
|
|
41
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module SpecHelper
|
|
4
|
+
|
|
5
|
+
def mock_model(*attributes)
|
|
6
|
+
Class.new {
|
|
7
|
+
include Equalizer.new(*attributes)
|
|
8
|
+
|
|
9
|
+
attributes.each { |attribute| attr_accessor attribute }
|
|
10
|
+
|
|
11
|
+
def initialize(attrs)
|
|
12
|
+
attrs.each { |name, value| send("#{name}=", value) }
|
|
13
|
+
end
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class TestMapper < Struct.new(:header, :model)
|
|
4
|
+
|
|
5
|
+
def call(relation)
|
|
6
|
+
relation
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def load(tuple)
|
|
10
|
+
model.new(
|
|
11
|
+
Hash[
|
|
12
|
+
header.map { |attribute| [attribute.name, tuple[attribute.name]] }
|
|
13
|
+
]
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def dump(object)
|
|
18
|
+
header.each_with_object([]) { |attribute, tuple|
|
|
19
|
+
tuple << object.send(attribute.name)
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Environment, '.setup' do
|
|
6
|
+
subject { described_class.setup(config) }
|
|
7
|
+
|
|
8
|
+
context 'when an environment is passed' do
|
|
9
|
+
let(:config) { environment }
|
|
10
|
+
let(:environment) { described_class.setup(test: 'memory://test') }
|
|
11
|
+
|
|
12
|
+
it { should be(environment) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context 'when a repository config hash is passed' do
|
|
16
|
+
let(:config) { { name => uri } }
|
|
17
|
+
let(:name) { :test }
|
|
18
|
+
let(:uri) { 'memory://test' }
|
|
19
|
+
|
|
20
|
+
let(:coerced_config) { Hash[test: Repository.build(name, coerced_uri)] }
|
|
21
|
+
let(:coerced_uri) { Addressable::URI.parse(uri) }
|
|
22
|
+
|
|
23
|
+
it { should eq(described_class.new(coerced_config, {})) }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Environment, '#[]' do
|
|
6
|
+
include_context 'Environment'
|
|
7
|
+
|
|
8
|
+
subject { object[:users] }
|
|
9
|
+
|
|
10
|
+
context 'when relation exists' do
|
|
11
|
+
fake(:relation, name: :users) { Axiom::Relation::Base }
|
|
12
|
+
|
|
13
|
+
before do
|
|
14
|
+
object[:users] = relation
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it { should be(relation) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'when relation does not exist' do
|
|
21
|
+
it { should be(nil) }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Environment, '#mapping' do
|
|
6
|
+
include_context 'Environment'
|
|
7
|
+
|
|
8
|
+
let!(:schema) do
|
|
9
|
+
object.schema do
|
|
10
|
+
base_relation(:users) do
|
|
11
|
+
repository :test
|
|
12
|
+
attribute :name, String
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
object.mapping do
|
|
19
|
+
users { map :name }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'sets up rom relations' do
|
|
24
|
+
expect(object[:users]).to be_instance_of(Relation)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Environment, '#repository' do
|
|
6
|
+
include_context 'Environment'
|
|
7
|
+
|
|
8
|
+
subject { object.repository(name) }
|
|
9
|
+
|
|
10
|
+
context 'when repository exists' do
|
|
11
|
+
let(:name) { :test }
|
|
12
|
+
|
|
13
|
+
it { should be_instance_of(Repository) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context 'when is not known' do
|
|
17
|
+
let(:name) { :not_here }
|
|
18
|
+
|
|
19
|
+
it { should be(nil) }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Environment, '#schema' do
|
|
6
|
+
let(:repositories) { Hash.new }
|
|
7
|
+
let(:object) { Environment.build(repositories) }
|
|
8
|
+
let(:block) { -> { } }
|
|
9
|
+
|
|
10
|
+
fake(:schema)
|
|
11
|
+
|
|
12
|
+
before do
|
|
13
|
+
fake_class(Schema, build: -> { schema })
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe 'with a block' do
|
|
17
|
+
subject { object.schema(&block) }
|
|
18
|
+
|
|
19
|
+
it 'calls the schema' do
|
|
20
|
+
expect(subject).to be(schema)
|
|
21
|
+
expect(schema).to have_received.call
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe 'without a block' do
|
|
26
|
+
subject { object.schema }
|
|
27
|
+
|
|
28
|
+
it 'calls the schema' do
|
|
29
|
+
expect(subject).to be(schema)
|
|
30
|
+
expect(schema).not_to have_received.call
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|