rom-mongo 0.1.0 → 0.2.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/.rspec +1 -0
- data/.travis.yml +15 -14
- data/CHANGELOG.md +15 -0
- data/Gemfile +6 -4
- data/README.md +4 -1
- data/Rakefile +1 -0
- data/lib/rom/mongo.rb +2 -1
- data/lib/rom/mongo/commands.rb +8 -2
- data/lib/rom/mongo/dataset.rb +84 -2
- data/lib/rom/mongo/gateway.rb +95 -0
- data/lib/rom/mongo/relation.rb +32 -0
- data/lib/rom/mongo/version.rb +1 -1
- data/rom-mongo.gemspec +4 -4
- data/spec/integration/gateway_spec.rb +105 -0
- data/spec/integration/inference_spec.rb +35 -0
- data/spec/shared/database.rb +8 -0
- data/spec/shared/users.rb +54 -0
- data/spec/spec_helper.rb +32 -9
- data/spec/unit/gateway_spec.rb +11 -0
- data/spec/unit/relation_spec.rb +33 -0
- metadata +44 -27
- data/lib/rom/mongo/repository.rb +0 -42
- data/spec/integration/repository_spec.rb +0 -128
- data/spec/unit/repository_spec.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 158a1091649ee8eabb19d094f2537965ea16d920
|
4
|
+
data.tar.gz: 7958f09445195f7b0a589045be6b473b5c935f29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: baf1b0460b2418e8c4692a77b1d51d5f37cbd2f635d6678ee85ecc8f4c6a3ac1f178d125d89abae0ee251fd9535f86ac27b25bcdb309ae9a92cd312f57b1d6ec
|
7
|
+
data.tar.gz: 26df9df0b2497306e270f656279a2393b6f1e2b38eaca5a7f6cd470f8cc20fcea9cfa83c97d0a2f7782effcabcd01a7895564cd9778291075a7b55795e4840e0
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -1,25 +1,26 @@
|
|
1
1
|
language: ruby
|
2
|
-
|
2
|
+
dist: trusty
|
3
|
+
sudo: required
|
3
4
|
cache: bundler
|
5
|
+
services:
|
6
|
+
- mongodb
|
4
7
|
bundler_args: --without yard guard benchmarks tools
|
5
|
-
|
6
|
-
|
7
|
-
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
8
|
-
- CODECLIMATE_REPO_TOKEN=886f3b795e74159719804f8e18b853f4c23a81bd814404e52ec248a0dae6d656
|
8
|
+
after_success:
|
9
|
+
- '[ -d coverage ] && bundle exec codeclimate-test-reporter'
|
9
10
|
script: "bundle exec rake ci"
|
10
11
|
rvm:
|
11
|
-
- 2.
|
12
|
-
- 2.
|
13
|
-
-
|
12
|
+
- 2.2.6
|
13
|
+
- 2.3.3
|
14
|
+
- 2.4.1
|
15
|
+
- rbx-3
|
14
16
|
- jruby
|
15
|
-
|
16
|
-
|
17
|
+
env:
|
18
|
+
global:
|
19
|
+
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
20
|
+
- COVERAGE='true'
|
17
21
|
matrix:
|
18
22
|
allow_failures:
|
19
|
-
- rvm:
|
20
|
-
- rvm: jruby-head
|
21
|
-
services:
|
22
|
-
- mongodb
|
23
|
+
- rvm: rbx-3
|
23
24
|
notifications:
|
24
25
|
webhooks:
|
25
26
|
urls:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## v0.2.0 2017-04-07
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* Added `Relation#by_pk` for compability with `rom-repo`'s command compiler (flash-gordon)
|
6
|
+
* Support fot inferring relations from collection list (flash-gordon)
|
7
|
+
* Support for ordered queries with `Relation#order` (flash-gordon)
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
* Updated to use official mongo driver (kwando)
|
12
|
+
* `Dataset` uses origin's querable interface now rather than forwarding to collection (kwando)
|
13
|
+
|
14
|
+
[Compare v0.1.0...v0.2.0](https://github.com/rom-rb/rom-mongo/compare/v0.1.0...v0.2.0)
|
15
|
+
|
1
16
|
## v0.1.0 2014-12-23
|
2
17
|
|
3
18
|
Update to work with ROM 0.6.0
|
data/Gemfile
CHANGED
@@ -2,12 +2,14 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
gem 'rom', git: 'https://github.com/rom-rb/rom.git', branch: 'master'
|
6
|
+
gem 'rom-repository', git: 'https://github.com/rom-rb/rom-repository.git', branch: 'master'
|
7
|
+
|
5
8
|
group :test do
|
6
9
|
gem 'inflecto'
|
7
|
-
gem '
|
8
|
-
gem '
|
9
|
-
gem '
|
10
|
-
gem 'virtus'
|
10
|
+
gem 'codeclimate-test-reporter', require: false, platforms: :mri
|
11
|
+
gem 'dry-struct'
|
12
|
+
gem 'byebug', platforms: :mri
|
11
13
|
end
|
12
14
|
|
13
15
|
group :tools do
|
data/README.md
CHANGED
@@ -33,7 +33,10 @@ Or install it yourself as:
|
|
33
33
|
|
34
34
|
## Usage
|
35
35
|
|
36
|
-
See [spec/integration/
|
36
|
+
See [spec/integration/gateway_spec.rb](spec/integration/gateway_spec.rb) for a sample usage.
|
37
|
+
|
38
|
+
## Issues
|
39
|
+
Issues should be reported in the main ROM repository, [https://github.com/rom-rb/rom/issues](https://github.com/rom-rb/rom/issues)
|
37
40
|
|
38
41
|
## License
|
39
42
|
|
data/Rakefile
CHANGED
data/lib/rom/mongo.rb
CHANGED
data/lib/rom/mongo/commands.rb
CHANGED
@@ -6,6 +6,8 @@ module ROM
|
|
6
6
|
module Mongo
|
7
7
|
module Commands
|
8
8
|
class Create < ROM::Commands::Create
|
9
|
+
adapter :mongo
|
10
|
+
|
9
11
|
def collection
|
10
12
|
relation.dataset
|
11
13
|
end
|
@@ -17,6 +19,8 @@ module ROM
|
|
17
19
|
end
|
18
20
|
|
19
21
|
class Update < ROM::Commands::Update
|
22
|
+
adapter :mongo
|
23
|
+
|
20
24
|
def collection
|
21
25
|
relation.dataset
|
22
26
|
end
|
@@ -28,9 +32,11 @@ module ROM
|
|
28
32
|
end
|
29
33
|
|
30
34
|
class Delete < ROM::Commands::Delete
|
35
|
+
adapter :mongo
|
36
|
+
|
31
37
|
def execute
|
32
|
-
removed =
|
33
|
-
|
38
|
+
removed = relation.to_a
|
39
|
+
relation.dataset.remove_all
|
34
40
|
removed
|
35
41
|
end
|
36
42
|
end
|
data/lib/rom/mongo/dataset.rb
CHANGED
@@ -1,9 +1,91 @@
|
|
1
|
-
require '
|
1
|
+
require 'origin'
|
2
2
|
|
3
3
|
module ROM
|
4
4
|
module Mongo
|
5
5
|
class Dataset
|
6
|
-
|
6
|
+
class Criteria
|
7
|
+
include Origin::Queryable
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(collection, criteria = Criteria.new)
|
11
|
+
@collection = collection
|
12
|
+
@criteria = criteria
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :collection
|
16
|
+
|
17
|
+
attr_reader :criteria
|
18
|
+
|
19
|
+
def find(criteria = {})
|
20
|
+
Dataset.new(collection, Criteria.new.where(criteria))
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_a
|
24
|
+
view.to_a
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def each
|
29
|
+
view.each { |doc| yield(doc) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def insert(data)
|
33
|
+
collection.insert_one(data)
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_all(attributes)
|
37
|
+
view.update_many(attributes)
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove_all
|
41
|
+
view.delete_many
|
42
|
+
end
|
43
|
+
|
44
|
+
def where(doc)
|
45
|
+
dataset(criteria.where(doc))
|
46
|
+
end
|
47
|
+
|
48
|
+
def only(fields)
|
49
|
+
dataset(criteria.only(fields))
|
50
|
+
end
|
51
|
+
|
52
|
+
def without(fields)
|
53
|
+
dataset(criteria.without(fields))
|
54
|
+
end
|
55
|
+
|
56
|
+
def limit(limit)
|
57
|
+
dataset(criteria.limit(limit))
|
58
|
+
end
|
59
|
+
|
60
|
+
def skip(value)
|
61
|
+
dataset(criteria.skip(value))
|
62
|
+
end
|
63
|
+
|
64
|
+
def order(value)
|
65
|
+
dataset(criteria.order(value))
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def view
|
71
|
+
with_options(collection.find(criteria.selector), criteria.options)
|
72
|
+
end
|
73
|
+
|
74
|
+
def dataset(criteria)
|
75
|
+
Dataset.new(collection, criteria)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Applies given options to the view
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
def with_options(view, options)
|
82
|
+
map = { fields: :projection }
|
83
|
+
options.each do |option, value|
|
84
|
+
option = map.fetch(option, option)
|
85
|
+
view = view.send(option, value) if view.respond_to?(option)
|
86
|
+
end
|
87
|
+
view
|
88
|
+
end
|
7
89
|
end
|
8
90
|
end
|
9
91
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
require 'rom/gateway'
|
5
|
+
|
6
|
+
require 'rom/mongo/dataset'
|
7
|
+
require 'rom/mongo/commands'
|
8
|
+
|
9
|
+
module ROM
|
10
|
+
module Mongo
|
11
|
+
class Gateway < ROM::Gateway
|
12
|
+
adapter :mongo
|
13
|
+
|
14
|
+
attr_reader :collections
|
15
|
+
|
16
|
+
# @!attribute [r] options
|
17
|
+
# @return [Hash] Gateway options
|
18
|
+
attr_reader :options
|
19
|
+
|
20
|
+
# Initialize an Mongo gateway
|
21
|
+
#
|
22
|
+
# Gateways are typically initialized via ROM::Configuration object, gateway constructor
|
23
|
+
# arguments such as URI and options are passed directly to this constructor
|
24
|
+
#
|
25
|
+
# @overload initialize(uri)
|
26
|
+
# Connects to a database via URI
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# ROM.container(:mongo, 'mongodb://127.0.0.1:27017/db_name')
|
30
|
+
#
|
31
|
+
# @param [String] uri connection URI
|
32
|
+
#
|
33
|
+
# @overload initialize(uri, options)
|
34
|
+
# Connects to a database via URI and options
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# ROM.container(:mongo, 'mongodb://127.0.0.1:27017/db_name', inferrable_relations: %i[users posts])
|
38
|
+
#
|
39
|
+
# @param [String,Symbol] uri connection URI
|
40
|
+
#
|
41
|
+
# @param [Hash] options connection options
|
42
|
+
#
|
43
|
+
# @option options [Array<Symbol>] :inferrable_relations
|
44
|
+
# A list of collection names that should be inferred. If
|
45
|
+
# this is set explicitly to an empty array relations
|
46
|
+
# won't be inferred at all
|
47
|
+
#
|
48
|
+
# @option options [Array<Symbol>] :not_inferrable_relations
|
49
|
+
# A list of collection names that should NOT be inferred
|
50
|
+
#
|
51
|
+
# @overload initialize(connection)
|
52
|
+
# Creates a gateway from an existing database connection.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# ROM.container(:mongo, Mongo::Client.new('mongodb://127.0.0.1:27017/db_name'))
|
56
|
+
#
|
57
|
+
# @param [Mongo::Client] connection a connection instance
|
58
|
+
#
|
59
|
+
# @return [Mongo::Gateway]
|
60
|
+
#
|
61
|
+
# @see https://docs.mongodb.com/ruby-driver/master/ MongoDB driver docs
|
62
|
+
#
|
63
|
+
# @api public
|
64
|
+
def initialize(uri, options = EMPTY_HASH)
|
65
|
+
@connection = uri.is_a?(::Mongo::Client) ? uri : ::Mongo::Client.new(uri, options)
|
66
|
+
@collections = {}
|
67
|
+
end
|
68
|
+
|
69
|
+
# List of defined collections
|
70
|
+
#
|
71
|
+
# @return [Array<Symbol>] An array with dataset names
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def schema
|
75
|
+
connection.database.collection_names.map(&:to_sym)
|
76
|
+
end
|
77
|
+
|
78
|
+
def [](name)
|
79
|
+
collections.fetch(name)
|
80
|
+
end
|
81
|
+
|
82
|
+
def dataset(name)
|
83
|
+
collections[name] = Dataset.new(connection[name])
|
84
|
+
end
|
85
|
+
|
86
|
+
def dataset?(name)
|
87
|
+
connection.database.collection_names.include?(name.to_s)
|
88
|
+
end
|
89
|
+
|
90
|
+
def command_namespace
|
91
|
+
Mongo::Commands
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rom/plugins/relation/key_inference'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module Mongo
|
5
|
+
class Relation < ROM::Relation
|
6
|
+
# @api private
|
7
|
+
def self.inherited(klass)
|
8
|
+
super
|
9
|
+
|
10
|
+
klass.auto_curry :by_pk
|
11
|
+
end
|
12
|
+
|
13
|
+
adapter :mongo
|
14
|
+
|
15
|
+
use :key_inference
|
16
|
+
|
17
|
+
forward :insert, :find, :only, :without, :skip, :limit, :where, :order
|
18
|
+
|
19
|
+
# @!method by_pk(id)
|
20
|
+
# Return a relation restricted by _id
|
21
|
+
#
|
22
|
+
# @param id [BSON::ObjectId] Document's PK value
|
23
|
+
#
|
24
|
+
# @return [Mongo::Relation]
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
def by_pk(id)
|
28
|
+
find(_id: id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/rom/mongo/version.rb
CHANGED
data/rom-mongo.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'rom/mongo/version'
|
@@ -18,11 +17,12 @@ Gem::Specification.new do |spec|
|
|
18
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
18
|
spec.require_paths = ["lib"]
|
20
19
|
|
21
|
-
spec.add_runtime_dependency "
|
22
|
-
spec.add_runtime_dependency "
|
23
|
-
spec.add_runtime_dependency "
|
20
|
+
spec.add_runtime_dependency "rom", "~> 3.2"
|
21
|
+
spec.add_runtime_dependency "mongo", "~> 2.2"
|
22
|
+
spec.add_runtime_dependency "origin"
|
24
23
|
|
25
24
|
spec.add_development_dependency "bundler"
|
26
25
|
spec.add_development_dependency "rake"
|
27
26
|
spec.add_development_dependency "rubocop", "~> 0.28.0"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.5"
|
28
28
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rom-repository'
|
3
|
+
|
4
|
+
RSpec.describe 'Mongo gateway' do
|
5
|
+
include_context 'database'
|
6
|
+
include_context 'users'
|
7
|
+
|
8
|
+
let(:gateway) { container.gateways[:default] }
|
9
|
+
|
10
|
+
describe 'env#relation' do
|
11
|
+
it 'returns mapped object' do
|
12
|
+
jane = users.as(:model).by_name('Jane').one!
|
13
|
+
|
14
|
+
expect(jane.id)
|
15
|
+
.to eql(container.relation(:users) { |r| r.find(name: 'Jane') }.one['_id'].to_s)
|
16
|
+
|
17
|
+
expect(jane.name).to eql('Jane')
|
18
|
+
expect(jane.email).to eql('jane@doe.org')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'with a repository' do
|
23
|
+
let(:repo) do
|
24
|
+
Class.new(ROM::Repository[:users]) do
|
25
|
+
commands :create, update: :by_pk
|
26
|
+
end.new(container)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns auto-mapped structs' do
|
30
|
+
jane = repo.users.by_name('Jane').one!
|
31
|
+
|
32
|
+
expect(jane._id.to_s)
|
33
|
+
.to eql(container.relation(:users) { |r| r.find(name: 'Jane') }.one['_id'].to_s)
|
34
|
+
|
35
|
+
expect(jane.name).to eql('Jane')
|
36
|
+
expect(jane.email).to eql('jane@doe.org')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'uses #by_pk for update commands' do
|
40
|
+
repo.update(jane_id, name: 'Jane Doe')
|
41
|
+
|
42
|
+
expect(repo.users.by_pk(jane_id).one!.name).to eql('Jane Doe')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'gateway#dataset?' do
|
47
|
+
it 'returns true if a collection exists' do
|
48
|
+
expect(gateway.dataset?(:users)).to be(true)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns false if a does not collection exist' do
|
52
|
+
expect(gateway.dataset?(:not_here)).to be(false)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'commands' do
|
57
|
+
let(:commands) { container.command(:users) }
|
58
|
+
|
59
|
+
describe 'create' do
|
60
|
+
it 'inserts a document into collection' do
|
61
|
+
id = BSON::ObjectId.new
|
62
|
+
|
63
|
+
result = commands.try do
|
64
|
+
commands.create.call(_id: id, name: 'joe', email: 'a.joe@doe.org')
|
65
|
+
end
|
66
|
+
|
67
|
+
expect(result)
|
68
|
+
.to match_array([{ _id: id, name: 'joe', email: 'a.joe@doe.org' }])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'update' do
|
73
|
+
it 'updates a document in the collection' do
|
74
|
+
jane = container.relation(:users).as(:model).by_name('Jane').one!
|
75
|
+
|
76
|
+
result = commands.try do
|
77
|
+
commands.update.by_name('Jane').call(email: 'jane.doe@test.com')
|
78
|
+
end
|
79
|
+
|
80
|
+
expect(result).to match_array(
|
81
|
+
[{ '_id' => BSON::ObjectId.from_string(jane.id),
|
82
|
+
'name' => 'Jane',
|
83
|
+
'email' => 'jane.doe@test.com' }]
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'delete' do
|
89
|
+
it 'deletes documents from the collection' do
|
90
|
+
jane = container.relation(:users).as(:model).by_name('Jane').one!
|
91
|
+
joe = container.relation(:users).as(:model).by_name('Joe').one!
|
92
|
+
|
93
|
+
result = commands.try { commands.delete.by_name('Joe') }
|
94
|
+
|
95
|
+
expect(result).to match_array(
|
96
|
+
[{ '_id' => BSON::ObjectId.from_string(joe.id),
|
97
|
+
'name' => 'Joe',
|
98
|
+
'email' => 'a.joe@doe.org' }]
|
99
|
+
)
|
100
|
+
|
101
|
+
expect(container.relation(:users).as(:model).all).to match_array([jane])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rom-repository'
|
3
|
+
|
4
|
+
RSpec.describe 'relation inference' do
|
5
|
+
include_context 'database'
|
6
|
+
|
7
|
+
before do
|
8
|
+
connection.database[:posts].create
|
9
|
+
connection.database[:tasks].create
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
connection.database[:posts].drop
|
14
|
+
connection.database[:tasks].drop
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'infers all relations by default' do
|
18
|
+
expect(container.relation(:posts)).to be_kind_of(ROM::Mongo::Relation)
|
19
|
+
expect(container.relation(:tasks)).to be_kind_of(ROM::Mongo::Relation)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'infers configured relations' do
|
23
|
+
configuration.config.gateways.default.inferrable_relations = [:posts]
|
24
|
+
|
25
|
+
expect(container.relations.elements.key?(:tasks)).to be(false)
|
26
|
+
expect(container.relation(:posts)).to be_kind_of(ROM::Mongo::Relation)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'skips configured relations' do
|
30
|
+
configuration.config.gateways.default.not_inferrable_relations = [:posts]
|
31
|
+
|
32
|
+
expect(container.relations.elements.key?(:posts)).to be(false)
|
33
|
+
expect(container.relation(:tasks)).to be_kind_of(ROM::Mongo::Relation)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
RSpec.shared_context 'database' do
|
2
|
+
let(:container) { ROM.container(configuration) }
|
3
|
+
let(:configuration) { ROM::Configuration.new(:mongo, connection) }
|
4
|
+
let(:connection) { ::Mongo::Client.new(MONGO_URI) }
|
5
|
+
|
6
|
+
let(:users) { container.relation(:users) }
|
7
|
+
let(:jane_id) { BSON::ObjectId.new }
|
8
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'dry-struct'
|
2
|
+
|
3
|
+
RSpec.shared_context 'users' do
|
4
|
+
let(:users) { container.relation(:users) }
|
5
|
+
let(:jane_id) { BSON::ObjectId.new }
|
6
|
+
|
7
|
+
before do
|
8
|
+
connection[:users].drop
|
9
|
+
|
10
|
+
configuration.relation(:users) do
|
11
|
+
schema do
|
12
|
+
# TODO: we need ROM::Mongo::Types (similar to ROM::SQL::Types)
|
13
|
+
attribute :_id, ROM::Types.Definition(BSON::ObjectId)
|
14
|
+
attribute :name, ROM::Types::String
|
15
|
+
attribute :email, ROM::Types::String
|
16
|
+
end
|
17
|
+
|
18
|
+
def by_name(name)
|
19
|
+
find(name: name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def all
|
23
|
+
find
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
configuration.commands(:users) do
|
28
|
+
define(:create)
|
29
|
+
define(:update)
|
30
|
+
define(:delete)
|
31
|
+
end
|
32
|
+
|
33
|
+
user_model = Class.new(Dry::Struct) do
|
34
|
+
attribute :id, 'coercible.string'
|
35
|
+
attribute :name, 'strict.string'
|
36
|
+
attribute :email, 'strict.string'
|
37
|
+
end
|
38
|
+
|
39
|
+
configuration.mappers do
|
40
|
+
define(:users) do
|
41
|
+
model(user_model)
|
42
|
+
|
43
|
+
register_as :model
|
44
|
+
|
45
|
+
attribute :id, from: '_id'
|
46
|
+
attribute :name, from: 'name'
|
47
|
+
attribute :email, from: 'email'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
container.relations.users.insert(_id: jane_id, name: 'Jane', email: 'jane@doe.org')
|
52
|
+
container.relations.users.insert(name: 'Joe', email: 'a.joe@doe.org')
|
53
|
+
end
|
54
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,23 +1,46 @@
|
|
1
|
-
|
1
|
+
if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
|
2
|
+
require 'yaml'
|
3
|
+
rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
|
4
|
+
latest_mri = rubies.select { |v| v =~ /\A\d+\.\d+.\d+\z/ }.max
|
2
5
|
|
3
|
-
if
|
4
|
-
|
5
|
-
|
6
|
+
if RUBY_VERSION == latest_mri
|
7
|
+
require 'simplecov'
|
8
|
+
SimpleCov.start do
|
9
|
+
add_filter '/spec/'
|
10
|
+
end
|
11
|
+
end
|
6
12
|
end
|
7
13
|
|
8
14
|
require 'rom-mongo'
|
9
15
|
|
16
|
+
begin
|
17
|
+
require 'byebug'
|
18
|
+
rescue LoadError
|
19
|
+
end
|
20
|
+
|
21
|
+
MONGO_URI = 'mongodb://127.0.0.1:27017/rom_mongo'.freeze
|
22
|
+
|
23
|
+
Mongo::Logger.logger = Logger.new(nil)
|
24
|
+
|
10
25
|
root = Pathname(__FILE__).dirname
|
11
26
|
|
12
|
-
|
27
|
+
# Namespace holding all objects created during specs
|
28
|
+
module Test
|
29
|
+
def self.remove_constants
|
30
|
+
constants.each(&method(:remove_const))
|
31
|
+
end
|
32
|
+
end
|
13
33
|
|
14
34
|
RSpec.configure do |config|
|
15
|
-
config.
|
16
|
-
|
35
|
+
config.disable_monkey_patching!
|
36
|
+
|
37
|
+
config.before(:suite) do
|
38
|
+
::Mongo::Client.new(MONGO_URI).database.drop
|
17
39
|
end
|
18
40
|
|
19
41
|
config.after do
|
20
|
-
|
21
|
-
added_constants.each { |name| Object.send(:remove_const, name) }
|
42
|
+
Test.remove_constants
|
22
43
|
end
|
23
44
|
end
|
45
|
+
|
46
|
+
Dir[root.join('shared/*.rb').to_s].each { |f| require f }
|
@@ -0,0 +1,33 @@
|
|
1
|
+
RSpec.describe ROM::Mongo::Relation do
|
2
|
+
include_context 'database'
|
3
|
+
include_context 'users'
|
4
|
+
|
5
|
+
describe '#by_pk' do
|
6
|
+
it 'fetches a document by _id' do
|
7
|
+
expect(users.by_pk(jane_id).one!).
|
8
|
+
to eql(
|
9
|
+
'_id' => jane_id,
|
10
|
+
'name' => 'Jane',
|
11
|
+
'email' => 'jane@doe.org'
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#order' do
|
17
|
+
it 'sorts documents' do
|
18
|
+
expect(users.order(name: :asc).only(:name).without(:_id).to_a).
|
19
|
+
to eql([{'name' => 'Jane',}, {'name' => 'Joe'}])
|
20
|
+
|
21
|
+
expect(users.order(name: :desc).only(:name).without(:_id).to_a).
|
22
|
+
to eql([{'name' => 'Joe',}, {'name' => 'Jane'}])
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'supports mutli-field sorting' do
|
26
|
+
expect(users.order(name: :asc, email: :asc).only(:name).without(:_id).to_a).
|
27
|
+
to eql([{'name' => 'Jane',}, {'name' => 'Joe'}])
|
28
|
+
|
29
|
+
expect(users.order(email: :asc, name: :asc).only(:name).without(:_id).to_a).
|
30
|
+
to eql([{'name' => 'Joe',}, {'name' => 'Jane'}])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,63 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rom-mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rom
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '3.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '3.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: mongo
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '2.2'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '2.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: origin
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0.6'
|
48
45
|
- - ">="
|
49
46
|
- !ruby/object:Gem::Version
|
50
|
-
version: 0
|
47
|
+
version: '0'
|
51
48
|
type: :runtime
|
52
49
|
prerelease: false
|
53
50
|
version_requirements: !ruby/object:Gem::Requirement
|
54
51
|
requirements:
|
55
|
-
- - "~>"
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
version: '0.6'
|
58
52
|
- - ">="
|
59
53
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0
|
54
|
+
version: '0'
|
61
55
|
- !ruby/object:Gem::Dependency
|
62
56
|
name: bundler
|
63
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,6 +94,20 @@ dependencies:
|
|
100
94
|
- - "~>"
|
101
95
|
- !ruby/object:Gem::Version
|
102
96
|
version: 0.28.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.5'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.5'
|
103
111
|
description: MongoDB support for Ruby Object Mapper
|
104
112
|
email:
|
105
113
|
- piotr.solnica@gmail.com
|
@@ -121,12 +129,17 @@ files:
|
|
121
129
|
- lib/rom/mongo.rb
|
122
130
|
- lib/rom/mongo/commands.rb
|
123
131
|
- lib/rom/mongo/dataset.rb
|
124
|
-
- lib/rom/mongo/
|
132
|
+
- lib/rom/mongo/gateway.rb
|
133
|
+
- lib/rom/mongo/relation.rb
|
125
134
|
- lib/rom/mongo/version.rb
|
126
135
|
- rom-mongo.gemspec
|
127
|
-
- spec/integration/
|
136
|
+
- spec/integration/gateway_spec.rb
|
137
|
+
- spec/integration/inference_spec.rb
|
138
|
+
- spec/shared/database.rb
|
139
|
+
- spec/shared/users.rb
|
128
140
|
- spec/spec_helper.rb
|
129
|
-
- spec/unit/
|
141
|
+
- spec/unit/gateway_spec.rb
|
142
|
+
- spec/unit/relation_spec.rb
|
130
143
|
homepage: ''
|
131
144
|
licenses:
|
132
145
|
- MIT
|
@@ -147,11 +160,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
160
|
version: '0'
|
148
161
|
requirements: []
|
149
162
|
rubyforge_project:
|
150
|
-
rubygems_version: 2.
|
163
|
+
rubygems_version: 2.6.11
|
151
164
|
signing_key:
|
152
165
|
specification_version: 4
|
153
166
|
summary: MongoDB support for Ruby Object Mapper
|
154
167
|
test_files:
|
155
|
-
- spec/integration/
|
168
|
+
- spec/integration/gateway_spec.rb
|
169
|
+
- spec/integration/inference_spec.rb
|
170
|
+
- spec/shared/database.rb
|
171
|
+
- spec/shared/users.rb
|
156
172
|
- spec/spec_helper.rb
|
157
|
-
- spec/unit/
|
173
|
+
- spec/unit/gateway_spec.rb
|
174
|
+
- spec/unit/relation_spec.rb
|
data/lib/rom/mongo/repository.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'moped'
|
2
|
-
require 'uri'
|
3
|
-
|
4
|
-
require 'rom/repository'
|
5
|
-
|
6
|
-
require 'rom/mongo/dataset'
|
7
|
-
require 'rom/mongo/commands'
|
8
|
-
|
9
|
-
module ROM
|
10
|
-
module Mongo
|
11
|
-
class Relation < ROM::Relation
|
12
|
-
forward :insert, :find
|
13
|
-
end
|
14
|
-
|
15
|
-
class Repository < ROM::Repository
|
16
|
-
attr_reader :collections
|
17
|
-
|
18
|
-
def initialize(uri)
|
19
|
-
host, database = uri.split('/')
|
20
|
-
@connection = Moped::Session.new([host])
|
21
|
-
@connection.use database
|
22
|
-
@collections = {}
|
23
|
-
end
|
24
|
-
|
25
|
-
def [](name)
|
26
|
-
collections.fetch(name)
|
27
|
-
end
|
28
|
-
|
29
|
-
def dataset(name)
|
30
|
-
collections[name] = Dataset.new(connection[name])
|
31
|
-
end
|
32
|
-
|
33
|
-
def dataset?(name)
|
34
|
-
connection.collection_names.include?(name.to_s)
|
35
|
-
end
|
36
|
-
|
37
|
-
def command_namespace
|
38
|
-
Mongo::Commands
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,128 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'virtus'
|
4
|
-
|
5
|
-
describe 'Mongo repository' do
|
6
|
-
subject(:rom) { setup.finalize }
|
7
|
-
|
8
|
-
let(:setup) { ROM.setup(:mongo, '127.0.0.1:27017/test') }
|
9
|
-
let(:repository) { rom.repositories[:default] }
|
10
|
-
|
11
|
-
after do
|
12
|
-
repository.connection.drop
|
13
|
-
end
|
14
|
-
|
15
|
-
before do
|
16
|
-
setup.relation(:users) do
|
17
|
-
def by_name(name)
|
18
|
-
find(name: name)
|
19
|
-
end
|
20
|
-
|
21
|
-
def all
|
22
|
-
find
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
setup.commands(:users) do
|
27
|
-
define(:create)
|
28
|
-
define(:update)
|
29
|
-
define(:delete)
|
30
|
-
end
|
31
|
-
|
32
|
-
user_model = Class.new do
|
33
|
-
include Virtus.value_object
|
34
|
-
|
35
|
-
values do
|
36
|
-
attribute :id, String
|
37
|
-
attribute :name, String
|
38
|
-
attribute :email, String
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
setup.mappers do
|
43
|
-
define(:users) do
|
44
|
-
model(user_model)
|
45
|
-
|
46
|
-
register_as :model
|
47
|
-
|
48
|
-
attribute :id, from: '_id'
|
49
|
-
attribute :name, from: 'name'
|
50
|
-
attribute :email, from: 'email'
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
rom.relations.users.insert(name: 'Jane', email: 'jane@doe.org')
|
55
|
-
rom.relations.users.insert(name: 'Joe', email: 'joe@doe.org')
|
56
|
-
end
|
57
|
-
|
58
|
-
describe 'env#relation' do
|
59
|
-
it 'returns mapped object' do
|
60
|
-
jane = rom.relation(:users).as(:model).by_name('Jane').one!
|
61
|
-
|
62
|
-
expect(jane.id)
|
63
|
-
.to eql(rom.relation(:users) { |r| r.find(name: 'Jane') }.one['_id'].to_s)
|
64
|
-
expect(jane.name).to eql('Jane')
|
65
|
-
expect(jane.email).to eql('jane@doe.org')
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe 'repository#dataset?' do
|
70
|
-
it 'returns true if a collection exists' do
|
71
|
-
expect(repository.dataset?(:users)).to be(true)
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'returns false if a does not collection exist' do
|
75
|
-
expect(repository.dataset?(:not_here)).to be(false)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe 'commands' do
|
80
|
-
let(:commands) { rom.command(:users) }
|
81
|
-
|
82
|
-
describe 'create' do
|
83
|
-
it 'inserts a document into collection' do
|
84
|
-
id = BSON::ObjectId.new
|
85
|
-
|
86
|
-
result = commands.try do
|
87
|
-
commands.create.call(_id: id, name: 'joe', email: 'joe@doe.org')
|
88
|
-
end
|
89
|
-
|
90
|
-
expect(result)
|
91
|
-
.to match_array([{ _id: id, name: 'joe', email: 'joe@doe.org' }])
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
describe 'update' do
|
96
|
-
it 'updates a document in the collection' do
|
97
|
-
jane = rom.relation(:users).as(:model).by_name('Jane').one!
|
98
|
-
|
99
|
-
result = commands.try do
|
100
|
-
commands.update.by_name('Jane').set(email: 'jane.doe@test.com')
|
101
|
-
end
|
102
|
-
|
103
|
-
expect(result).to match_array(
|
104
|
-
[{ '_id' => BSON::ObjectId.from_string(jane.id),
|
105
|
-
'name' => 'Jane',
|
106
|
-
'email' => 'jane.doe@test.com' }]
|
107
|
-
)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe 'delete' do
|
112
|
-
it 'deletes documents from the collection' do
|
113
|
-
jane = rom.relation(:users).as(:model).by_name('Jane').one!
|
114
|
-
joe = rom.relation(:users).as(:model).by_name('Joe').one!
|
115
|
-
|
116
|
-
result = commands.try { commands.delete.by_name('Joe') }
|
117
|
-
|
118
|
-
expect(result).to match_array(
|
119
|
-
[{ '_id' => BSON::ObjectId.from_string(joe.id),
|
120
|
-
'name' => 'Joe',
|
121
|
-
'email' => 'joe@doe.org' }]
|
122
|
-
)
|
123
|
-
|
124
|
-
expect(rom.relation(:users).as(:model).all).to match_array([jane])
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|