rmodel 0.2.2.pre.dev → 0.3.0.pre.dev
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/.gitignore +1 -0
- data/README.md +54 -1
- data/examples/sql_repository.rb +42 -0
- data/lib/rmodel/sequel/repository.rb +61 -0
- data/lib/rmodel/sequel/repository_ext/query.rb +34 -0
- data/lib/rmodel/sequel/repository_ext/queryable.rb +30 -0
- data/lib/rmodel/sequel/setup.rb +12 -0
- data/lib/rmodel/sequel/simple_factory.rb +28 -0
- data/lib/rmodel/setup.rb +1 -0
- data/lib/rmodel/version.rb +1 -1
- data/lib/rmodel.rb +3 -0
- data/rmodel.gemspec +2 -0
- data/spec/rmodel/mongo/repository_ext/queryable_spec.rb +1 -1
- data/spec/rmodel/mongo/repository_spec.rb +50 -0
- data/spec/rmodel/sequel/repository_ext/queryable_spec.rb +114 -0
- data/spec/rmodel/sequel/repository_initialize_spec.rb +118 -0
- data/spec/rmodel/sequel/repository_spec.rb +64 -0
- data/spec/rmodel/sequel/simple_factory_spec.rb +55 -0
- data/spec/shared/clean_moped.rb +1 -1
- data/spec/shared/clean_sequel.rb +11 -0
- data/spec/shared/repository_ext/crud.rb +83 -0
- data/spec/shared/repository_ext/sugarable.rb +28 -30
- data/spec/shared/repository_ext/timestampable.rb +43 -45
- metadata +50 -8
- data/spec/rmodel/mongo/repository_crud_spec.rb +0 -90
- data/spec/rmodel/mongo/repository_ext/sugarable_spec.rb +0 -14
- data/spec/rmodel/mongo/repository_ext/timestampable_spec.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 790c3d9b1e832db25110443277f43ecc7dc8c195
|
4
|
+
data.tar.gz: 075fb90b667ce3efc49e772366039173439c3941
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c70ec6448d74876b0fc8e82598e9ba695d03b6d57321925b66db79928789c6c89a09c3d9d87f6f680b9cc60abf77a185eb33c139782e21d4c4744f3c998b59f5
|
7
|
+
data.tar.gz: f6137976d4574443696e365ad4165d5bff58cd2960174776c7baafe4faa6fd7c77b286194617c49b9c967d3bdf2ae2ef55205723985c081fbe13894272ad2615
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -9,10 +9,11 @@
|
|
9
9
|
* [Timestamps](#timestamps)
|
10
10
|
* [Sugar methods](#sugar-methods)
|
11
11
|
* [Advanced creation of repository](#advanced-creation-of-repository)
|
12
|
+
* [SQL repository](#sql-repository)
|
12
13
|
|
13
14
|
Rmodel is an ORM library, which tends to follow the SOLID principles.
|
14
15
|
|
15
|
-
**Currently works with MongoDB
|
16
|
+
**Currently works with MongoDB and SQL databases supported by Sequel.**
|
16
17
|
|
17
18
|
The main thoughts behind it are:
|
18
19
|
|
@@ -228,6 +229,58 @@ repo.find(1)
|
|
228
229
|
|
229
230
|
The `factory` is an object, which has 2 methods: `#fromHash(hash)` and `#toHash(object)`.
|
230
231
|
|
232
|
+
### SQL repository
|
233
|
+
|
234
|
+
SQL amenities is based on the Sequel gem (http://sequel.jeremyevans.net/).
|
235
|
+
So the big range of SQL databases is supported.
|
236
|
+
|
237
|
+
> Sequel currently has adapters for ADO, Amalgalite, CUBRID, DataObjects, IBM_DB, JDBC, MySQL, Mysql2, ODBC, Oracle, PostgreSQL, SQLAnywhere, SQLite3, Swift, and TinyTDS.
|
238
|
+
|
239
|
+
Below you can the the example how to setup Rmodel for any supported SQL database.
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
require 'rmodel'
|
243
|
+
|
244
|
+
Rmodel.setup do
|
245
|
+
client :default, { adapter: 'sqlite', database: 'rmodel_test.sqlite3' }
|
246
|
+
end
|
247
|
+
|
248
|
+
client = Rmodel.setup.establish_sequel_client(:default)
|
249
|
+
client.drop_table? :things
|
250
|
+
client.create_table :things do
|
251
|
+
primary_key :id
|
252
|
+
String :name
|
253
|
+
Float :price
|
254
|
+
end
|
255
|
+
|
256
|
+
class Thing
|
257
|
+
attr_accessor :id, :name, :price
|
258
|
+
|
259
|
+
def initialize(name = nil, price = nil)
|
260
|
+
self.name = name
|
261
|
+
self.price = price
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
class ThingRepository < Rmodel::Sequel::Repository
|
266
|
+
simple_factory Thing, :name, :price
|
267
|
+
|
268
|
+
scope :worth_more_than do |amount|
|
269
|
+
# use Sequel dataset filtering http://sequel.jeremyevans.net/rdoc/files/doc/dataset_filtering_rdoc.html
|
270
|
+
where { price >= amount }
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
repo = ThingRepository.new
|
275
|
+
repo.insert Thing.new('iPod', 200)
|
276
|
+
repo.insert Thing.new('iPhone', 300)
|
277
|
+
repo.insert Thing.new('iPad', 500)
|
278
|
+
|
279
|
+
p repo.query.count # 3
|
280
|
+
p repo.query.worth_more_than(400).count # 1
|
281
|
+
p repo.query.worth_more_than(400).to_sql
|
282
|
+
```
|
283
|
+
|
231
284
|
## Contributing
|
232
285
|
|
233
286
|
1. Fork it ( https://github.com/alexei-lexx/rmodel/fork )
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rmodel'
|
2
|
+
|
3
|
+
Rmodel.setup do
|
4
|
+
# see more examples of connection options
|
5
|
+
# http://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html#label-Passing+a+block+to+either+method
|
6
|
+
client :default, { adapter: 'sqlite', database: 'rmodel_test.sqlite3' }
|
7
|
+
end
|
8
|
+
|
9
|
+
client = Rmodel.setup.establish_sequel_client(:default)
|
10
|
+
client.drop_table? :things
|
11
|
+
client.create_table :things do
|
12
|
+
primary_key :id
|
13
|
+
String :name
|
14
|
+
Float :price
|
15
|
+
end
|
16
|
+
|
17
|
+
class Thing
|
18
|
+
attr_accessor :id, :name, :price
|
19
|
+
|
20
|
+
def initialize(name = nil, price = nil)
|
21
|
+
self.name = name
|
22
|
+
self.price = price
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class ThingRepository < Rmodel::Sequel::Repository
|
27
|
+
simple_factory Thing, :name, :price
|
28
|
+
|
29
|
+
scope :worth_more_than do |amount|
|
30
|
+
# use Sequel dataset filtering http://sequel.jeremyevans.net/rdoc/files/doc/dataset_filtering_rdoc.html
|
31
|
+
where { price >= amount }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
repo = ThingRepository.new
|
36
|
+
repo.insert Thing.new('iPod', 200)
|
37
|
+
repo.insert Thing.new('iPhone', 300)
|
38
|
+
repo.insert Thing.new('iPad', 500)
|
39
|
+
|
40
|
+
p repo.query.count # 3
|
41
|
+
p repo.query.worth_more_than(400).count # 1
|
42
|
+
p repo.query.worth_more_than(400).to_sql
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
require 'rmodel/base/repository'
|
3
|
+
require 'rmodel/sequel/repository_ext/queryable'
|
4
|
+
|
5
|
+
module Rmodel::Sequel
|
6
|
+
class Repository < Rmodel::Base::Repository
|
7
|
+
include RepositoryExt::Queryable
|
8
|
+
|
9
|
+
def initialize(client = nil, table = nil, factory = nil)
|
10
|
+
@client = client || Rmodel.setup.establish_sequel_client(self.class.client_name || :default) or
|
11
|
+
raise ArgumentError.new('Client driver is not setup')
|
12
|
+
|
13
|
+
@table = table || self.class.setting_table ||
|
14
|
+
self.class.table_by_convention or
|
15
|
+
raise ArgumentError.new('Table can not be guessed')
|
16
|
+
|
17
|
+
@factory = factory || self.class.setting_factory or
|
18
|
+
raise ArgumentError.new('Factory can not be guessed')
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(id)
|
22
|
+
result = @client[@table].where(id: id).first
|
23
|
+
result && @factory.fromHash(result)
|
24
|
+
end
|
25
|
+
|
26
|
+
def insert(object)
|
27
|
+
id = @client[@table].insert(@factory.toHash(object, true))
|
28
|
+
object.id ||= id
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(object)
|
32
|
+
@client[@table].where(id: object.id).update(@factory.toHash(object, false))
|
33
|
+
end
|
34
|
+
|
35
|
+
def remove(object)
|
36
|
+
@client[@table].where(id: object.id).delete
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
attr_reader :client_name, :setting_table, :setting_factory
|
41
|
+
|
42
|
+
def client(name)
|
43
|
+
@client_name = name
|
44
|
+
end
|
45
|
+
|
46
|
+
def table(name)
|
47
|
+
@setting_table = name
|
48
|
+
end
|
49
|
+
|
50
|
+
def table_by_convention
|
51
|
+
if name =~ /(.*)Repository$/
|
52
|
+
ActiveSupport::Inflector.tableize($1).to_sym
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def simple_factory(klass, *attributes)
|
57
|
+
@setting_factory = SimpleFactory.new(klass, *attributes)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'origin'
|
2
|
+
|
3
|
+
module Rmodel::Sequel
|
4
|
+
module RepositoryExt
|
5
|
+
class Query
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(repo, dataset)
|
9
|
+
@repo = repo
|
10
|
+
@dataset = dataset
|
11
|
+
end
|
12
|
+
|
13
|
+
def each(&block)
|
14
|
+
@repo.find_by_query(@dataset).each(&block)
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def remove
|
19
|
+
@dataset.delete
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_sql
|
23
|
+
@dataset.sql
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.define_scope(name, &block)
|
27
|
+
define_method name do |*args|
|
28
|
+
new_dataset = @dataset.instance_exec(*args, &block)
|
29
|
+
self.class.new(@repo, new_dataset)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rmodel/sequel/repository_ext/query'
|
2
|
+
|
3
|
+
module Rmodel::Sequel
|
4
|
+
module RepositoryExt
|
5
|
+
module Queryable
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
def query
|
11
|
+
(self.class.query_klass ||= Class.new(Query)).new(self, @client[@table])
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_by_query(dataset)
|
15
|
+
dataset.map do |hash|
|
16
|
+
@factory.fromHash(hash)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
attr_accessor :query_klass
|
22
|
+
|
23
|
+
def scope(name, &block)
|
24
|
+
self.query_klass ||= Class.new(Query)
|
25
|
+
self.query_klass.define_scope(name, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rmodel::Sequel
|
2
|
+
class SimpleFactory
|
3
|
+
def initialize(klass, *attributes)
|
4
|
+
@klass = klass
|
5
|
+
@attributes = attributes
|
6
|
+
end
|
7
|
+
|
8
|
+
def fromHash(hash)
|
9
|
+
object = @klass.new
|
10
|
+
object.id = hash[:id]
|
11
|
+
@attributes.each do |attribute|
|
12
|
+
object.public_send "#{attribute}=", hash[attribute.to_sym]
|
13
|
+
end
|
14
|
+
object
|
15
|
+
end
|
16
|
+
|
17
|
+
def toHash(object, id_included)
|
18
|
+
hash = {}
|
19
|
+
@attributes.each do |attribute|
|
20
|
+
hash[attribute.to_sym] = object.public_send(attribute)
|
21
|
+
end
|
22
|
+
if id_included
|
23
|
+
hash[:id] = object.id
|
24
|
+
end
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/rmodel/setup.rb
CHANGED
data/lib/rmodel/version.rb
CHANGED
data/lib/rmodel.rb
CHANGED
data/rmodel.gemspec
CHANGED
@@ -21,10 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency 'mongo', '~> 2.1'
|
22
22
|
spec.add_dependency 'activesupport'
|
23
23
|
spec.add_dependency 'origin'
|
24
|
+
spec.add_dependency 'sequel'
|
24
25
|
|
25
26
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
26
27
|
spec.add_development_dependency 'rake'
|
27
28
|
spec.add_development_dependency 'rspec'
|
29
|
+
spec.add_development_dependency 'sqlite3'
|
28
30
|
|
29
31
|
spec.required_ruby_version = '>= 2.0.0'
|
30
32
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
RSpec.describe Rmodel::Mongo::Repository do
|
2
|
+
it_behaves_like 'repository crud' do
|
3
|
+
include_context 'clean mongo database'
|
4
|
+
|
5
|
+
before do
|
6
|
+
stub_const('ThingRepository', Class.new(Rmodel::Mongo::Repository))
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:factory) { Rmodel::Mongo::SimpleFactory.new(Thing, :name) }
|
10
|
+
subject { ThingRepository.new(mongo_session, :things, factory) }
|
11
|
+
let(:unique_constraint_error) { Mongo::Error::OperationFailure }
|
12
|
+
|
13
|
+
def insert_record(id, columns)
|
14
|
+
record = columns.dup
|
15
|
+
record['_id'] = id
|
16
|
+
mongo_session[:things].insert_one(record)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it_behaves_like 'sugarable repository' do
|
21
|
+
include_context 'clean mongo database'
|
22
|
+
|
23
|
+
before do
|
24
|
+
stub_const('ThingRepository', Class.new(Rmodel::Mongo::Repository))
|
25
|
+
end
|
26
|
+
|
27
|
+
subject do
|
28
|
+
factory = Rmodel::Mongo::SimpleFactory.new(Thing, :name)
|
29
|
+
ThingRepository.new(mongo_session, :things, factory)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it_behaves_like 'timestampable repository' do
|
34
|
+
include_context 'clean mongo database'
|
35
|
+
|
36
|
+
before do
|
37
|
+
stub_const('ThingRepository', Class.new(Rmodel::Mongo::Repository))
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:repo_w_timestamps) do
|
41
|
+
factory = Rmodel::Mongo::SimpleFactory.new(Thing, :name, :created_at, :updated_at)
|
42
|
+
ThingRepository.new(mongo_session, :things, factory)
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:repo_wo_timestamps) do
|
46
|
+
factory = Rmodel::Mongo::SimpleFactory.new(Thing, :name)
|
47
|
+
ThingRepository.new(mongo_session, :things, factory)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
RSpec.describe Rmodel::Sequel::Repository do
|
2
|
+
include_context 'clean sequel database'
|
3
|
+
|
4
|
+
before do
|
5
|
+
create_database
|
6
|
+
stub_const('Thing', Struct.new(:id, :a, :b))
|
7
|
+
stub_const('ThingRepository', Class.new(Rmodel::Sequel::Repository))
|
8
|
+
end
|
9
|
+
|
10
|
+
subject do
|
11
|
+
factory = Rmodel::Sequel::SimpleFactory.new(Thing, :a, :b)
|
12
|
+
ThingRepository.new(sequel_conn, :things, factory)
|
13
|
+
end
|
14
|
+
|
15
|
+
before do
|
16
|
+
subject.insert(Thing.new(nil, 2, 3))
|
17
|
+
subject.insert(Thing.new(nil, 2, 4))
|
18
|
+
subject.insert(Thing.new(nil, 5, 6))
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.scope' do
|
22
|
+
context 'when a scope w/o arguments is defined' do
|
23
|
+
before do
|
24
|
+
ThingRepository.class_eval do
|
25
|
+
scope :a_equals_2 do
|
26
|
+
where(a: 2)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'works!' do
|
32
|
+
expect(subject.query.a_equals_2.count).to eq 2
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns an array of instances of the appropriate class' do
|
36
|
+
expect(subject.query.a_equals_2.first).to be_an_instance_of Thing
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when a scope w/ arguments is defined' do
|
41
|
+
before do
|
42
|
+
ThingRepository.class_eval do
|
43
|
+
scope :a_equals do |n|
|
44
|
+
where(a: n)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'works!' do
|
50
|
+
expect(subject.query.a_equals(2).count).to eq 2
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when two scopes are defined and chained' do
|
55
|
+
before do
|
56
|
+
ThingRepository.class_eval do
|
57
|
+
scope :a_equals do |n|
|
58
|
+
where(a: n)
|
59
|
+
end
|
60
|
+
|
61
|
+
scope :b_equals do |n|
|
62
|
+
where(b: n)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'works!' do
|
68
|
+
expect(subject.query.a_equals(2).b_equals(4).count).to eq 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when an unknown scope is used' do
|
73
|
+
it 'raises the NoMethodError' do
|
74
|
+
expect {
|
75
|
+
subject.query.something
|
76
|
+
}.to raise_error NoMethodError
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '.query' do
|
82
|
+
describe '#remove' do
|
83
|
+
context 'when no scope is given' do
|
84
|
+
it 'removes all objects' do
|
85
|
+
subject.query.remove
|
86
|
+
expect(subject.query.count).to eq 0
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when the scope filters 2 objects from 3' do
|
91
|
+
before do
|
92
|
+
ThingRepository.class_eval do
|
93
|
+
scope :a_equals_2 do
|
94
|
+
where(a: 2)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'removes 2 objects' do
|
100
|
+
subject.query.a_equals_2.remove
|
101
|
+
expect(subject.query.count).to eq 1
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def create_database
|
108
|
+
sequel_conn.create_table(:things) do
|
109
|
+
primary_key :id
|
110
|
+
Integer :a
|
111
|
+
Integer :b
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
RSpec.describe Rmodel::Sequel::Repository do
|
2
|
+
before do
|
3
|
+
stub_const('Thing', Struct.new(:id, :name))
|
4
|
+
stub_const('ThingRepository', Class.new(Rmodel::Sequel::Repository))
|
5
|
+
ThingRepository.send :attr_reader, :client, :table, :factory
|
6
|
+
end
|
7
|
+
let(:factory) { Rmodel::Sequel::SimpleFactory.new(Thing, :name) }
|
8
|
+
|
9
|
+
describe '.client(name)' do
|
10
|
+
conn_options = { adapter: 'sqlite', database: 'rmodel_test.sqlite3' }
|
11
|
+
|
12
|
+
subject { ThingRepository.new(nil, :things, factory) }
|
13
|
+
|
14
|
+
context 'when it is called with an existent name' do
|
15
|
+
before do
|
16
|
+
Rmodel.setup do
|
17
|
+
client :not_default, conn_options
|
18
|
+
end
|
19
|
+
|
20
|
+
ThingRepository.class_eval do
|
21
|
+
client :not_default
|
22
|
+
end
|
23
|
+
end
|
24
|
+
after { Rmodel::setup.clear }
|
25
|
+
|
26
|
+
it 'sets the appropriate #client' do
|
27
|
+
expect(subject.client).to be_a_kind_of Sequel::Database
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when it is called with a non-existent name' do
|
32
|
+
before do
|
33
|
+
ThingRepository.class_eval do
|
34
|
+
client :not_default
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'makes #initialize raise the ArgumentError' do
|
39
|
+
expect { subject }.to raise_error ArgumentError
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when it is not called' do
|
44
|
+
context 'when the :default client is set' do
|
45
|
+
before do
|
46
|
+
Rmodel.setup do
|
47
|
+
client :default, conn_options
|
48
|
+
end
|
49
|
+
end
|
50
|
+
after { Rmodel::setup.clear }
|
51
|
+
|
52
|
+
it 'sets #client to be default' do
|
53
|
+
expect(subject.client).to be_a_kind_of Sequel::Database
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when the :default client is not set' do
|
58
|
+
it 'makes #initialize raise the ArgumentError' do
|
59
|
+
expect { subject }.to raise_error ArgumentError
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '.table(name)' do
|
66
|
+
subject { ThingRepository.new(Object.new, nil, factory) }
|
67
|
+
|
68
|
+
context 'when the :people table is given' do
|
69
|
+
before do
|
70
|
+
ThingRepository.class_eval do
|
71
|
+
table :people
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'uses the :people' do
|
76
|
+
expect(subject.table).to eq :people
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when no table is given' do
|
81
|
+
it 'gets the right name by convention' do
|
82
|
+
expect(subject.table).to eq :things
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '.simple_factory(klass, attribute1, attribute2, ...)' do
|
88
|
+
subject { ThingRepository.new(Object.new, :things) }
|
89
|
+
|
90
|
+
context 'when it is called' do
|
91
|
+
before do
|
92
|
+
ThingRepository.class_eval do
|
93
|
+
simple_factory Thing, :name, :email
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'sets the appropriate #factory' do
|
98
|
+
expect(subject.factory).to be_an_instance_of Rmodel::Sequel::SimpleFactory
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when it is not called' do
|
103
|
+
it 'make #initialize raise an error' do
|
104
|
+
expect { subject }.to raise_error ArgumentError
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#initialize(client, collection, factory)' do
|
110
|
+
context 'when all constructor arguments are passed' do
|
111
|
+
it 'works!' do
|
112
|
+
expect {
|
113
|
+
ThingRepository.new(Object.new, :users, factory)
|
114
|
+
}.not_to raise_error
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
RSpec.describe Rmodel::Sequel::Repository do
|
2
|
+
it_behaves_like 'repository crud' do
|
3
|
+
include_examples 'clean sequel database'
|
4
|
+
|
5
|
+
before do
|
6
|
+
create_database
|
7
|
+
stub_const('ThingRepository', Class.new(Rmodel::Sequel::Repository))
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:factory) { Rmodel::Sequel::SimpleFactory.new(Thing, :name) }
|
11
|
+
subject { ThingRepository.new(sequel_conn, :things, factory) }
|
12
|
+
let(:unique_constraint_error) { Sequel::UniqueConstraintViolation }
|
13
|
+
|
14
|
+
def insert_record(id, columns)
|
15
|
+
record = columns.dup
|
16
|
+
record[:id] = id
|
17
|
+
sequel_conn[:things].insert(record)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it_behaves_like 'sugarable repository' do
|
22
|
+
include_examples 'clean sequel database'
|
23
|
+
|
24
|
+
before do
|
25
|
+
create_database
|
26
|
+
stub_const('ThingRepository', Class.new(Rmodel::Sequel::Repository))
|
27
|
+
end
|
28
|
+
|
29
|
+
subject do
|
30
|
+
factory = Rmodel::Sequel::SimpleFactory.new(Thing, :name)
|
31
|
+
ThingRepository.new(sequel_conn, :things, factory)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it_behaves_like 'timestampable repository' do
|
36
|
+
include_examples 'clean sequel database'
|
37
|
+
|
38
|
+
before do
|
39
|
+
create_database(true)
|
40
|
+
stub_const('ThingRepository', Class.new(Rmodel::Sequel::Repository))
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:repo_w_timestamps) do
|
44
|
+
factory = Rmodel::Sequel::SimpleFactory.new(Thing, :name, :created_at, :updated_at)
|
45
|
+
ThingRepository.new(sequel_conn, :things, factory)
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:repo_wo_timestamps) do
|
49
|
+
factory = Rmodel::Sequel::SimpleFactory.new(Thing, :name)
|
50
|
+
ThingRepository.new(sequel_conn, :things, factory)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_database(timestamps = false)
|
55
|
+
sequel_conn.create_table(:things) do
|
56
|
+
primary_key :id
|
57
|
+
String :name
|
58
|
+
if timestamps
|
59
|
+
Time :created_at
|
60
|
+
Time :updated_at
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
RSpec.describe Rmodel::Sequel::SimpleFactory do
|
2
|
+
context 'when the User(id, name, email) class is defined' do
|
3
|
+
before { stub_const('User', Struct.new(:id, :name, :email)) }
|
4
|
+
|
5
|
+
subject { described_class.new(User, :name, :email) }
|
6
|
+
|
7
|
+
describe '#fromHash' do
|
8
|
+
context 'when the hash with id, name and email is given' do
|
9
|
+
let(:hash) { { id: 1, name: 'John', email: 'john@example.com' } }
|
10
|
+
let(:result) { subject.fromHash(hash) }
|
11
|
+
|
12
|
+
it 'returns an instance of User' do
|
13
|
+
expect(result).to be_an_instance_of User
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'sets the attributes correctly' do
|
17
|
+
expect(result.name).to eq 'John'
|
18
|
+
expect(result.email).to eq 'john@example.com'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'sets the User#id correctly' do
|
22
|
+
expect(result.id).to eq 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#toHash' do
|
28
|
+
let(:user) { User.new(1, 'John', 'john@example.com') }
|
29
|
+
context 'when id_included is false' do
|
30
|
+
let(:result) { subject.toHash(user, false) }
|
31
|
+
|
32
|
+
it 'returns an instance of Hash' do
|
33
|
+
expect(result).to be_an_instance_of Hash
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sets the keys correctly' do
|
37
|
+
expect(result[:name]).to eq 'John'
|
38
|
+
expect(result[:email]).to eq 'john@example.com'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'has no the "id" key' do
|
42
|
+
expect(result.has_key?(:id)).to be false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when id_included is true' do
|
47
|
+
let(:result) { subject.toHash(user, true) }
|
48
|
+
|
49
|
+
it 'sets the "id" key' do
|
50
|
+
expect(result[:id]).to eq 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/shared/clean_moped.rb
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
RSpec.shared_context 'clean sequel database' do
|
2
|
+
let(:sequel_conn) { Sequel.connect(adapter: 'sqlite', database: 'rmodel_test.sqlite3') }
|
3
|
+
|
4
|
+
before(:all) do
|
5
|
+
Mongo::Logger.logger.level = Logger::ERROR
|
6
|
+
sequel_conn = Sequel.sqlite('rmodel_test.sqlite3')
|
7
|
+
sequel_conn.drop_table?(:users, :things)
|
8
|
+
end
|
9
|
+
|
10
|
+
after { sequel_conn.drop_table?(:users, :things) }
|
11
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
RSpec.shared_examples 'repository crud' do
|
2
|
+
before do
|
3
|
+
stub_const('Thing', Struct.new(:id, :name))
|
4
|
+
end
|
5
|
+
|
6
|
+
describe '#find' do
|
7
|
+
before { insert_record(1, name: 'chair') }
|
8
|
+
|
9
|
+
context 'when an existent id is given' do
|
10
|
+
it 'returns the instance of correct type' do
|
11
|
+
expect(subject.find(1)).to be_an_instance_of Thing
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns the correct attributes' do
|
15
|
+
expect(subject.find(1).name).to eq 'chair'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when a non-existent id is given' do
|
20
|
+
it 'returns nil' do
|
21
|
+
expect(subject.find(2)).to be_nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#insert' do
|
27
|
+
context 'when the id is not provided' do
|
28
|
+
let(:thing) { Thing.new(nil, 'chair') }
|
29
|
+
|
30
|
+
it 'sets the id before insert' do
|
31
|
+
subject.insert(thing)
|
32
|
+
expect(thing.id).not_to be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'persists the object' do
|
36
|
+
subject.insert(thing)
|
37
|
+
expect(subject.find(thing.id).name).to eq 'chair'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when the id is provided' do
|
42
|
+
let(:thing) { Thing.new(1000, 'chair') }
|
43
|
+
|
44
|
+
it 'uses the existent id' do
|
45
|
+
subject.insert(thing)
|
46
|
+
expect(thing.id).to eq 1000
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when the given id already exists' do
|
51
|
+
let(:thing) { Thing.new }
|
52
|
+
before { subject.insert(thing) }
|
53
|
+
|
54
|
+
it 'raises the error' do
|
55
|
+
expect { subject.insert(thing) }.to raise_error unique_constraint_error
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#update' do
|
61
|
+
let(:thing) { Thing.new(nil) }
|
62
|
+
|
63
|
+
before do
|
64
|
+
subject.insert(thing)
|
65
|
+
thing.name = 'chair'
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'updates the record' do
|
69
|
+
subject.update(thing)
|
70
|
+
expect(subject.find(thing.id).name).to eq 'chair'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#remove' do
|
75
|
+
let(:thing) { Thing.new }
|
76
|
+
before { subject.insert(thing) }
|
77
|
+
|
78
|
+
it 'removes the record' do
|
79
|
+
subject.remove(thing)
|
80
|
+
expect(subject.find(thing.id)).to be_nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -1,45 +1,43 @@
|
|
1
1
|
RSpec.shared_examples 'sugarable repository' do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
end
|
2
|
+
before do
|
3
|
+
stub_const('Thing', Struct.new(:id, :name))
|
4
|
+
end
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
describe '#find!' do
|
7
|
+
context 'when an existent id is given' do
|
8
|
+
before { subject.insert(Thing.new(1)) }
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
end
|
10
|
+
it 'returns the right instance' do
|
11
|
+
expect(subject.find!(1)).not_to be_nil
|
14
12
|
end
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
15
|
+
context 'when a non-existent id is given' do
|
16
|
+
it 'raises NotFound' do
|
17
|
+
expect {
|
18
|
+
subject.find!(1)
|
19
|
+
}.to raise_error Rmodel::NotFound
|
22
20
|
end
|
23
21
|
end
|
22
|
+
end
|
24
23
|
|
25
|
-
|
26
|
-
|
24
|
+
describe 'save' do
|
25
|
+
let(:thing) { Thing.new }
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
27
|
+
context 'when a new object is given' do
|
28
|
+
it 'gets inserted' do
|
29
|
+
subject.save(thing)
|
30
|
+
expect(subject.find(thing.id)).not_to be_nil
|
33
31
|
end
|
32
|
+
end
|
34
33
|
|
35
|
-
|
36
|
-
|
34
|
+
context 'when an existent object is given' do
|
35
|
+
before { subject.insert(thing) }
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
37
|
+
it 'gets updated' do
|
38
|
+
thing.name = 'chair'
|
39
|
+
subject.save(thing)
|
40
|
+
expect(subject.find(thing.id).name).to eq 'chair'
|
43
41
|
end
|
44
42
|
end
|
45
43
|
end
|
@@ -1,68 +1,66 @@
|
|
1
1
|
RSpec.shared_examples 'timestampable repository' do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
subject { repo_w_timestamps }
|
9
|
-
|
10
|
-
context 'when we insert(object)' do
|
11
|
-
context 'and the object.created_at is already set' do
|
12
|
-
let(:thing) { Thing.new(nil, 'chair', Time.now) }
|
2
|
+
context 'when the entity object has attributes created_at and updated_at' do
|
3
|
+
before do
|
4
|
+
stub_const('Thing', Struct.new(:id, :name, :created_at, :updated_at))
|
5
|
+
end
|
13
6
|
|
14
|
-
|
15
|
-
set_created_at = thing.created_at
|
16
|
-
subject.insert(thing)
|
17
|
-
expect(thing.created_at).to eq set_created_at
|
18
|
-
end
|
19
|
-
end
|
7
|
+
subject { repo_w_timestamps }
|
20
8
|
|
21
|
-
|
22
|
-
|
9
|
+
context 'when we insert(object)' do
|
10
|
+
context 'and the object.created_at is already set' do
|
11
|
+
let(:thing) { Thing.new(nil, 'chair', Time.now) }
|
23
12
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
13
|
+
it 'doesnt change the value of created_at' do
|
14
|
+
set_created_at = thing.created_at
|
15
|
+
subject.insert(thing)
|
16
|
+
expect(thing.created_at).to eq set_created_at
|
28
17
|
end
|
29
18
|
end
|
30
19
|
|
31
|
-
context '
|
20
|
+
context 'and the object.created_at is not set yet' do
|
32
21
|
let(:thing) { Thing.new(nil, 'chair') }
|
33
|
-
before { subject.insert(thing) }
|
34
22
|
|
35
23
|
it 'sets the value of created_at' do
|
36
|
-
thing
|
37
|
-
|
38
|
-
expect(thing.updated_at).not_to be_nil
|
24
|
+
subject.insert(thing)
|
25
|
+
expect(thing.created_at).not_to be_nil
|
39
26
|
end
|
40
27
|
end
|
41
28
|
end
|
42
29
|
|
43
|
-
context 'when
|
44
|
-
|
45
|
-
|
30
|
+
context 'when we update(object)' do
|
31
|
+
let(:thing) { Thing.new(nil, 'chair') }
|
32
|
+
before { subject.insert(thing) }
|
33
|
+
|
34
|
+
it 'sets the value of created_at' do
|
35
|
+
thing.name = 'table'
|
36
|
+
subject.update(thing)
|
37
|
+
expect(thing.updated_at).not_to be_nil
|
46
38
|
end
|
39
|
+
end
|
40
|
+
end
|
47
41
|
|
48
|
-
|
49
|
-
|
42
|
+
context 'when the entity has no attributes :created_at and updated_at' do
|
43
|
+
before do
|
44
|
+
stub_const('Thing', Struct.new(:id, :name))
|
45
|
+
end
|
50
46
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
47
|
+
let(:thing) { Thing.new(nil, 'chair') }
|
48
|
+
subject { repo_wo_timestamps }
|
49
|
+
|
50
|
+
context 'when we insert(object)' do
|
51
|
+
it 'does nothing special' do
|
52
|
+
subject.insert(thing)
|
53
|
+
expect(thing.respond_to?(:created_at)).to be false
|
56
54
|
end
|
55
|
+
end
|
57
56
|
|
58
|
-
|
59
|
-
|
57
|
+
context 'when we update(object)' do
|
58
|
+
before { subject.insert(thing) }
|
60
59
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
60
|
+
it 'does nothing special' do
|
61
|
+
thing.name = 'table'
|
62
|
+
subject.update(thing)
|
63
|
+
expect(thing.respond_to?(:updated_at)).to be false
|
66
64
|
end
|
67
65
|
end
|
68
66
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rmodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0.pre.dev
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexei
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mongo
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sequel
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: bundler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +108,20 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
description: Rmodel is an ORM library, which tends to follow the SOLID principles.
|
98
126
|
email:
|
99
127
|
- alexei.lexx@gmail.com
|
@@ -109,6 +137,7 @@ files:
|
|
109
137
|
- README.md
|
110
138
|
- Rakefile
|
111
139
|
- examples/advanced_creation_of_repository.rb
|
140
|
+
- examples/sql_repository.rb
|
112
141
|
- examples/timestamps.rb
|
113
142
|
- examples/user.rb
|
114
143
|
- lib/rmodel.rb
|
@@ -121,17 +150,26 @@ files:
|
|
121
150
|
- lib/rmodel/mongo/repository_ext/queryable.rb
|
122
151
|
- lib/rmodel/mongo/setup.rb
|
123
152
|
- lib/rmodel/mongo/simple_factory.rb
|
153
|
+
- lib/rmodel/sequel/repository.rb
|
154
|
+
- lib/rmodel/sequel/repository_ext/query.rb
|
155
|
+
- lib/rmodel/sequel/repository_ext/queryable.rb
|
156
|
+
- lib/rmodel/sequel/setup.rb
|
157
|
+
- lib/rmodel/sequel/simple_factory.rb
|
124
158
|
- lib/rmodel/setup.rb
|
125
159
|
- lib/rmodel/version.rb
|
126
160
|
- rmodel.gemspec
|
127
|
-
- spec/rmodel/mongo/repository_crud_spec.rb
|
128
161
|
- spec/rmodel/mongo/repository_ext/queryable_spec.rb
|
129
|
-
- spec/rmodel/mongo/repository_ext/sugarable_spec.rb
|
130
|
-
- spec/rmodel/mongo/repository_ext/timestampable_spec.rb
|
131
162
|
- spec/rmodel/mongo/repository_initialize_spec.rb
|
163
|
+
- spec/rmodel/mongo/repository_spec.rb
|
132
164
|
- spec/rmodel/mongo/simple_factory_spec.rb
|
165
|
+
- spec/rmodel/sequel/repository_ext/queryable_spec.rb
|
166
|
+
- spec/rmodel/sequel/repository_initialize_spec.rb
|
167
|
+
- spec/rmodel/sequel/repository_spec.rb
|
168
|
+
- spec/rmodel/sequel/simple_factory_spec.rb
|
133
169
|
- spec/rmodel/setup_spec.rb
|
134
170
|
- spec/shared/clean_moped.rb
|
171
|
+
- spec/shared/clean_sequel.rb
|
172
|
+
- spec/shared/repository_ext/crud.rb
|
135
173
|
- spec/shared/repository_ext/sugarable.rb
|
136
174
|
- spec/shared/repository_ext/timestampable.rb
|
137
175
|
- spec/spec_helper.rb
|
@@ -160,14 +198,18 @@ signing_key:
|
|
160
198
|
specification_version: 4
|
161
199
|
summary: Rmodel is an ORM library, which tends to follow the SOLID principles.
|
162
200
|
test_files:
|
163
|
-
- spec/rmodel/mongo/repository_crud_spec.rb
|
164
201
|
- spec/rmodel/mongo/repository_ext/queryable_spec.rb
|
165
|
-
- spec/rmodel/mongo/repository_ext/sugarable_spec.rb
|
166
|
-
- spec/rmodel/mongo/repository_ext/timestampable_spec.rb
|
167
202
|
- spec/rmodel/mongo/repository_initialize_spec.rb
|
203
|
+
- spec/rmodel/mongo/repository_spec.rb
|
168
204
|
- spec/rmodel/mongo/simple_factory_spec.rb
|
205
|
+
- spec/rmodel/sequel/repository_ext/queryable_spec.rb
|
206
|
+
- spec/rmodel/sequel/repository_initialize_spec.rb
|
207
|
+
- spec/rmodel/sequel/repository_spec.rb
|
208
|
+
- spec/rmodel/sequel/simple_factory_spec.rb
|
169
209
|
- spec/rmodel/setup_spec.rb
|
170
210
|
- spec/shared/clean_moped.rb
|
211
|
+
- spec/shared/clean_sequel.rb
|
212
|
+
- spec/shared/repository_ext/crud.rb
|
171
213
|
- spec/shared/repository_ext/sugarable.rb
|
172
214
|
- spec/shared/repository_ext/timestampable.rb
|
173
215
|
- spec/spec_helper.rb
|
@@ -1,90 +0,0 @@
|
|
1
|
-
RSpec.describe Rmodel::Mongo::Repository do
|
2
|
-
include_context 'clean Mongo database'
|
3
|
-
|
4
|
-
before do
|
5
|
-
stub_const('User', Struct.new(:id, :name, :email))
|
6
|
-
stub_const('UserRepository', Class.new(Rmodel::Mongo::Repository))
|
7
|
-
end
|
8
|
-
|
9
|
-
let(:factory) { Rmodel::Mongo::SimpleFactory.new(User, :name, :email) }
|
10
|
-
subject(:repo) { UserRepository.new(mongo_session, :users, factory) }
|
11
|
-
|
12
|
-
describe '#find' do
|
13
|
-
context 'when an existent id is given' do
|
14
|
-
before do
|
15
|
-
mongo_session[:users].insert_one(_id: 1, name: 'John', email: 'john@example.com')
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'returns the instance of correct type' do
|
19
|
-
expect(repo.find(1)).to be_an_instance_of User
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
context 'when a non-existent id is given' do
|
24
|
-
it 'returns nil' do
|
25
|
-
expect(repo.find(1)).to be_nil
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe '#insert' do
|
31
|
-
context 'when the id is not provided' do
|
32
|
-
let(:user) { User.new(nil, 'John', 'john@example.com') }
|
33
|
-
|
34
|
-
it 'sets the id before insert' do
|
35
|
-
repo.insert(user)
|
36
|
-
expect(user.id).not_to be_nil
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'persists the object' do
|
40
|
-
repo.insert(user)
|
41
|
-
found = mongo_session[:users].find(name: 'John', email: 'john@example.com').count
|
42
|
-
expect(found).to eq 1
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context 'when the id is provided' do
|
47
|
-
let(:user) { User.new(1, 'John', 'john@example.com') }
|
48
|
-
|
49
|
-
it 'uses the existent id' do
|
50
|
-
repo.insert(user)
|
51
|
-
expect(user.id).to eq 1
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context 'when the given id already exists' do
|
56
|
-
let(:user) { User.new(nil, 'John', 'john@example.com') }
|
57
|
-
before { repo.insert(user) }
|
58
|
-
|
59
|
-
it 'raises the error' do
|
60
|
-
expect { repo.insert(user) }.to raise_error Mongo::Error::OperationFailure
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe '#update' do
|
66
|
-
let(:user) { User.new(nil, 'John', 'john@example.com') }
|
67
|
-
|
68
|
-
before do
|
69
|
-
repo.insert(user)
|
70
|
-
user.name = 'John Smith'
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'updates the record' do
|
74
|
-
repo.update(user)
|
75
|
-
found = mongo_session[:users].find(name: 'John Smith').count
|
76
|
-
expect(found).to eq 1
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
describe '#remove' do
|
81
|
-
let(:user) { User.new(nil, 'John', 'john@example.com') }
|
82
|
-
before { repo.insert(user) }
|
83
|
-
|
84
|
-
it 'removes the record' do
|
85
|
-
repo.remove(user)
|
86
|
-
found = mongo_session[:users].find(name: 'John').count
|
87
|
-
expect(found).to eq 0
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
RSpec.describe Rmodel::Mongo::Repository do
|
2
|
-
include_examples 'sugarable repository' do
|
3
|
-
include_context 'clean Mongo database'
|
4
|
-
|
5
|
-
before do
|
6
|
-
stub_const('ThingRepository', Class.new(Rmodel::Mongo::Repository))
|
7
|
-
end
|
8
|
-
|
9
|
-
subject do
|
10
|
-
factory = Rmodel::Mongo::SimpleFactory.new(Thing, :name)
|
11
|
-
ThingRepository.new(mongo_session, :things, factory)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
RSpec.describe Rmodel::Mongo::Repository do
|
2
|
-
include_examples 'timestampable repository' do
|
3
|
-
include_context 'clean Mongo database'
|
4
|
-
|
5
|
-
before do
|
6
|
-
stub_const('ThingRepository', Class.new(Rmodel::Mongo::Repository))
|
7
|
-
end
|
8
|
-
|
9
|
-
let(:repo_w_timestamps) do
|
10
|
-
factory = Rmodel::Mongo::SimpleFactory.new(Thing, :name, :created_at, :updated_at)
|
11
|
-
ThingRepository.new(mongo_session, :things, factory)
|
12
|
-
end
|
13
|
-
|
14
|
-
let(:repo_wo_timestamps) do
|
15
|
-
factory = Rmodel::Mongo::SimpleFactory.new(Thing, :name)
|
16
|
-
ThingRepository.new(mongo_session, :things, factory)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|