rmodel 0.2.2.pre.dev → 0.3.0.pre.dev
Sign up to get free protection for your applications and to get access to all the features.
- 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
|