couchrest_model 2.2.0.beta1 → 2.2.0.beta2
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/.travis.yml +7 -4
- data/Dockerfile +11 -0
- data/Gemfile +2 -0
- data/Guardfile +31 -0
- data/VERSION +1 -1
- data/couchrest_model.gemspec +2 -2
- data/docker-compose.yml +26 -0
- data/history.md +14 -1
- data/lib/couchrest/model/connection.rb +15 -20
- data/lib/couchrest/model/connection_config.rb +32 -0
- data/lib/couchrest/model/designs/migrations.rb +3 -0
- data/lib/couchrest/model/designs/view.rb +49 -34
- data/lib/couchrest/model/document_queries.rb +18 -5
- data/lib/couchrest/model/persistence.rb +3 -1
- data/lib/couchrest/model/proxyable.rb +12 -3
- data/lib/couchrest/model/server_pool.rb +22 -0
- data/lib/couchrest/model/support/couchrest_database.rb +1 -1
- data/lib/couchrest/model/utils/migrate.rb +8 -5
- data/lib/couchrest_model.rb +2 -0
- data/spec/spec_helper.rb +16 -1
- data/spec/unit/connection_config_spec.rb +41 -0
- data/spec/unit/connection_spec.rb +3 -8
- data/spec/unit/designs/migrations_spec.rb +1 -0
- data/spec/unit/designs/view_spec.rb +61 -43
- data/spec/unit/designs_spec.rb +0 -66
- data/spec/unit/persistence_spec.rb +7 -0
- data/spec/unit/proxyable_spec.rb +37 -2
- data/spec/unit/server_pool_spec.rb +31 -0
- data/spec/unit/support/couchrest_database_spec.rb +15 -0
- data/spec/unit/utils/migrate_spec.rb +136 -1
- metadata +22 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9da5f0b0e14df586c9cb3c85dea4f0b7de7263b
|
4
|
+
data.tar.gz: c921fb6038d169cc018f2144e7f64b233bedfd4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70086755f3a4955131dc7523b62a156812b1dbd53c748286fe7b4b0c87817ff68b106abfb2448d627c86f8089a894a261cabe127e2a08c6d34e084ddd0c711b2
|
7
|
+
data.tar.gz: 8c8099e69adc06ae21e634392be1f0bc4e1b629edf7cdb4e5a4fccf092ff93d4d662e25505ec0937bac6a80ac28d0b0867926274ec9cd8689d7ac0a97e808b90
|
data/.travis.yml
CHANGED
@@ -7,19 +7,22 @@ rvm:
|
|
7
7
|
- 2.2.4
|
8
8
|
- 2.1.10
|
9
9
|
- 2.0.0
|
10
|
-
- jruby
|
11
10
|
- rbx
|
12
11
|
services: couchdb
|
13
12
|
before_install:
|
14
13
|
- gem install bundler
|
15
|
-
env:
|
16
|
-
- JRUBY_OPTS=--2.0
|
17
14
|
matrix:
|
15
|
+
include:
|
16
|
+
# JRuby takes a lot more effort
|
17
|
+
- rvm: jruby-9.1.7.0
|
18
|
+
env: JRUBY_OPTS='--2.0'
|
19
|
+
gemfile: Gemfile.activesupport-4.x
|
18
20
|
allow_failures:
|
19
21
|
- rvm: 2.0.0
|
20
22
|
gemfile: Gemfile.activesupport-5.x
|
21
23
|
- rvm: 2.1.10
|
22
24
|
gemfile: Gemfile.activesupport-5.x
|
23
|
-
- rvm: jruby
|
25
|
+
- rvm: jruby-1.7.22
|
24
26
|
gemfile: Gemfile.activesupport-5.x
|
25
27
|
- rvm: rbx # Has problems with Array#insert inheritence
|
28
|
+
- rvm: jruby-9.1.7.0
|
data/Dockerfile
ADDED
data/Gemfile
CHANGED
data/Guardfile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features) \
|
6
|
+
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
7
|
+
|
8
|
+
## Note: if you are using the `directories` clause above and you are not
|
9
|
+
## watching the project directory ('.'), then you will want to move
|
10
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
11
|
+
#
|
12
|
+
# $ mkdir config
|
13
|
+
# $ mv Guardfile config/
|
14
|
+
# $ ln -s config/Guardfile .
|
15
|
+
#
|
16
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
17
|
+
|
18
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
19
|
+
# rspec may be run, below are examples of the most common uses.
|
20
|
+
# * bundler: 'bundle exec rspec'
|
21
|
+
# * bundler binstubs: 'bin/rspec'
|
22
|
+
# * spring: 'bin/rsspec' (This will use spring if running and you have
|
23
|
+
# installed the spring binstubs per the docs)
|
24
|
+
# * zeus: 'zeus rspec' (requires the server to be started separetly)
|
25
|
+
# * 'just' rspec: 'rspec'
|
26
|
+
guard :rspec, cmd: 'rspec' do
|
27
|
+
watch(%r{^spec/.+_spec\.rb$})
|
28
|
+
watch(%r{^lib/couchrest/model/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
|
29
|
+
watch('spec/spec_helper.rb') { "spec" }
|
30
|
+
end
|
31
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.2.0.
|
1
|
+
2.2.0.beta2
|
data/couchrest_model.gemspec
CHANGED
@@ -22,13 +22,13 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
23
|
s.require_paths = ["lib"]
|
24
24
|
|
25
|
-
s.add_dependency("couchrest", "2.0.
|
25
|
+
s.add_dependency("couchrest", "2.0.1")
|
26
26
|
s.add_dependency("activemodel", ">= 4.0.2")
|
27
27
|
s.add_dependency("tzinfo", ">= 0.3.22")
|
28
28
|
s.add_dependency("hashdiff", "~> 0.3")
|
29
29
|
s.add_development_dependency("rspec", "~> 3.5.0")
|
30
30
|
s.add_development_dependency("rack-test", ">= 0.5.7")
|
31
|
-
s.add_development_dependency("rake", ">= 0.8.0")
|
31
|
+
s.add_development_dependency("rake", ">= 0.8.0", "< 11.0")
|
32
32
|
s.add_development_dependency("test-unit")
|
33
33
|
s.add_development_dependency("minitest", "> 4.1") #, "< 5.0") # For Kaminari and activesupport, pending removal
|
34
34
|
s.add_development_dependency("kaminari", ">= 0.14.1", "< 0.16.0")
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
version: "2"
|
2
|
+
services:
|
3
|
+
test:
|
4
|
+
build:
|
5
|
+
context: .
|
6
|
+
entrypoint: ["bundle", "exec"]
|
7
|
+
command: ["rspec"]
|
8
|
+
environment:
|
9
|
+
RAILS_ENV: test
|
10
|
+
COUCH_HOST: "http://couch:5984/"
|
11
|
+
depends_on:
|
12
|
+
- couch
|
13
|
+
volumes:
|
14
|
+
- ./:/usr/lib/couchrest_model
|
15
|
+
networks:
|
16
|
+
- couchrest_model
|
17
|
+
couch:
|
18
|
+
image: couchdb:1.6
|
19
|
+
ports:
|
20
|
+
- "5984"
|
21
|
+
networks:
|
22
|
+
- couchrest_model
|
23
|
+
- default
|
24
|
+
networks:
|
25
|
+
couchrest_model:
|
26
|
+
driver: bridge
|
data/history.md
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
# CouchRest Model Change History
|
2
2
|
|
3
|
-
## 2.2.0.
|
3
|
+
## 2.2.0.beta2 - 2017-12-03
|
4
|
+
|
5
|
+
* Make View instance respond to model_name ([PR](https://github.com/couchrest/couchrest_model/pull/217) @adamcrown)
|
6
|
+
* Feature/proxyable custom databases ([PR](https://github.com/couchrest/couchrest_model/pull/218) @ellneal, @pacoguzman)
|
7
|
+
* Fix clear cache for delete db ([PR](https://github.com/couchrest/couchrest_model/pull/216) @MarkFull, @ktaragorn, @samlown)
|
8
|
+
* Migration improvements and tests ([PR](https://github.com/couchrest/couchrest_model/pull/215) @ellneal)
|
9
|
+
* Add some guards to prevent view errors when using custom emit values ([PR](https://github.com/couchrest/couchrest_model/pull/214) @ellneal)
|
10
|
+
* Making running the tests a bit easier using Docker ([PR](https://github.com/couchrest/couchrest_model/pull/213) @ellneal)
|
11
|
+
* Upgraded to Couchrest 2.0.1 ([PR](https://github.com/couchrest/couchrest_model/pull/220) @samlown)
|
12
|
+
* Removed :persistent and simplifying connection handling with aim to reduce number of connections and improve multithreading ([PR](https://github.com/couchrest/couchrest_model/pull/220) @samlown)
|
13
|
+
* Removed passing database in views and get calls, to simplify API. Use Proxying or instantiate objects manually to use a different database.([PR](https://github.com/couchrest/couchrest_model/pull/224) @samlown)
|
14
|
+
* Document#reload! now raises DocumentNotFound on deleted doc ([PR](https://github.com/couchrest/couchrest_model/pull/223) @azul)
|
15
|
+
|
16
|
+
## 2.2.0.beta1 - 2016-08-20
|
4
17
|
|
5
18
|
* Radical re-factor of dirty tracking using Hashdiff gem, providing reliable change detection with nested data. ([PR](https://github.com/couchrest/couchrest_model/pull/211) @samlown)
|
6
19
|
* Implement proxy for factory methods ([PR](https://github.com/couchrest/couchrest_model/pull/210) @ellneal)
|
@@ -9,33 +9,30 @@ module CouchRest
|
|
9
9
|
|
10
10
|
module ClassMethods
|
11
11
|
|
12
|
-
# Overwrite the
|
12
|
+
# Overwrite the CouchRest::Document.use_database method so that a database
|
13
13
|
# name can be provided instead of a full connection.
|
14
|
-
#
|
15
|
-
#
|
14
|
+
# We prepare the database immediatly, so ensure any connection details
|
15
|
+
# are provided in advance.
|
16
|
+
# Note that this will not work correctly with proxied models.
|
16
17
|
def use_database(db)
|
17
|
-
@
|
18
|
+
@database = prepare_database(db)
|
18
19
|
end
|
19
20
|
|
20
21
|
# Overwrite the default database method so that it always
|
21
22
|
# provides something from the configuration.
|
22
23
|
# It will try to inherit the database from an ancester
|
23
|
-
# unless the use_database method has been used
|
24
|
-
# case a new connection will be started.
|
24
|
+
# unless the use_database method has been used.
|
25
25
|
def database
|
26
26
|
@database ||= prepare_database(super)
|
27
27
|
end
|
28
28
|
|
29
29
|
def server
|
30
|
-
@server ||=
|
30
|
+
@server ||= ServerPool.instance[prepare_server_uri]
|
31
31
|
end
|
32
32
|
|
33
33
|
def prepare_database(db = nil)
|
34
|
-
db = @_use_database unless @_use_database.nil?
|
35
34
|
if db.nil? || db.is_a?(String) || db.is_a?(Symbol)
|
36
|
-
|
37
|
-
db = [conf[:prefix], db.to_s, conf[:suffix]].reject{|s| s.to_s.empty?}.join(conf[:join])
|
38
|
-
self.server.database!(db)
|
35
|
+
self.server.database!(prepare_database_name(db))
|
39
36
|
else
|
40
37
|
db
|
41
38
|
end
|
@@ -43,6 +40,11 @@ module CouchRest
|
|
43
40
|
|
44
41
|
protected
|
45
42
|
|
43
|
+
def prepare_database_name(base)
|
44
|
+
conf = connection_configuration
|
45
|
+
[conf[:prefix], base.to_s, conf[:suffix]].reject{|s| s.to_s.empty?}.join(conf[:join])
|
46
|
+
end
|
47
|
+
|
46
48
|
def prepare_server_uri
|
47
49
|
conf = connection_configuration
|
48
50
|
userinfo = [conf[:username], conf[:password]].compact.join(':')
|
@@ -52,21 +54,14 @@ module CouchRest
|
|
52
54
|
|
53
55
|
def connection_configuration
|
54
56
|
@connection_configuration ||=
|
55
|
-
self.connection.
|
57
|
+
self.connection.merge(
|
56
58
|
(load_connection_config_file[environment.to_sym] || {}).symbolize_keys
|
57
59
|
)
|
58
60
|
end
|
59
61
|
|
60
62
|
def load_connection_config_file
|
61
63
|
file = connection_config_file
|
62
|
-
|
63
|
-
(File.exists?(file) ?
|
64
|
-
YAML::load(ERB.new(IO.read(file)).result) :
|
65
|
-
{ }).symbolize_keys
|
66
|
-
end
|
67
|
-
|
68
|
-
def connection_config_cache
|
69
|
-
Thread.current[:connection_config_cache] ||= {}
|
64
|
+
ConnectionConfig.instance[file]
|
70
65
|
end
|
71
66
|
|
72
67
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module CouchRest
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Thead safe caching of connection configuration files.
|
5
|
+
class ConnectionConfig
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@config_files = {}
|
10
|
+
@mutex = Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](file)
|
14
|
+
@mutex.synchronize do
|
15
|
+
@config_files[file] ||= load_config(file)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def load_config(file)
|
22
|
+
if File.exists?(file)
|
23
|
+
YAML::load(ERB.new(IO.read(file)).result).symbolize_keys
|
24
|
+
else
|
25
|
+
{ }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -20,21 +20,21 @@ module CouchRest
|
|
20
20
|
# outside CouchRest Model.
|
21
21
|
def initialize(design_doc, parent, new_query = {}, name = nil)
|
22
22
|
self.design_doc = design_doc
|
23
|
-
|
24
|
-
#
|
23
|
+
|
24
|
+
# Extract options from query
|
25
25
|
proxy = new_query.delete(:proxy)
|
26
26
|
delete = new_query.delete(:delete)
|
27
27
|
|
28
28
|
if parent.is_a?(Class) && parent < CouchRest::Model::Base
|
29
29
|
raise "Name must be provided for view to be initialized" if name.nil?
|
30
|
-
self.
|
31
|
-
self.
|
30
|
+
self.owner = (proxy || parent)
|
31
|
+
self.model = parent
|
32
32
|
self.name = name.to_s
|
33
33
|
# Default options:
|
34
34
|
self.query = { }
|
35
35
|
elsif parent.is_a?(self.class)
|
36
|
-
self.
|
37
|
-
self.
|
36
|
+
self.owner = (proxy || parent.owner)
|
37
|
+
self.model = parent.model
|
38
38
|
self.name = parent.name
|
39
39
|
self.query = parent.query.dup
|
40
40
|
else
|
@@ -60,11 +60,11 @@ module CouchRest
|
|
60
60
|
return @rows if @rows
|
61
61
|
if block_given?
|
62
62
|
execute do |row|
|
63
|
-
yield ViewRow.new(row,
|
63
|
+
yield ViewRow.new(row, owner)
|
64
64
|
end
|
65
65
|
else
|
66
66
|
if execute && result['rows']
|
67
|
-
@rows ||= result['rows'].map{|v| ViewRow.new(v,
|
67
|
+
@rows ||= result['rows'].map{|v| ViewRow.new(v, owner)}
|
68
68
|
else
|
69
69
|
[ ]
|
70
70
|
end
|
@@ -334,12 +334,6 @@ module CouchRest
|
|
334
334
|
update_query(:stale => value.to_s)
|
335
335
|
end
|
336
336
|
|
337
|
-
# Specify the database the view should use. If not defined,
|
338
|
-
# an attempt will be made to load its value from the model.
|
339
|
-
def database(value)
|
340
|
-
update_query(:database => value)
|
341
|
-
end
|
342
|
-
|
343
337
|
# Set the view's proxy that will be used instead of the model
|
344
338
|
# for any future searches. As soon as this enters the
|
345
339
|
# new view's initializer it will be removed and set as the model
|
@@ -367,7 +361,7 @@ module CouchRest
|
|
367
361
|
#
|
368
362
|
|
369
363
|
def page(page)
|
370
|
-
limit(
|
364
|
+
limit(model.default_per_page).skip(model.default_per_page * ([page.to_i, 1].max - 1))
|
371
365
|
end
|
372
366
|
|
373
367
|
def per(num)
|
@@ -400,6 +394,18 @@ module CouchRest
|
|
400
394
|
(offset_value / limit_value) + 1
|
401
395
|
end
|
402
396
|
|
397
|
+
# == ActiveRecord compatibility support
|
398
|
+
|
399
|
+
# Return the model name for #model just as User::ActiveRecord_Relation
|
400
|
+
# would for better ActiveRecord interoperability
|
401
|
+
def model_name
|
402
|
+
ActiveModel::Name.new(model)
|
403
|
+
end
|
404
|
+
|
405
|
+
def database
|
406
|
+
owner.database
|
407
|
+
end
|
408
|
+
|
403
409
|
protected
|
404
410
|
|
405
411
|
def include_docs!
|
@@ -421,20 +427,16 @@ module CouchRest
|
|
421
427
|
!design_doc['views'][name]['reduce'].blank?
|
422
428
|
end
|
423
429
|
|
424
|
-
def use_database
|
425
|
-
query[:database] || model.database
|
426
|
-
end
|
427
|
-
|
428
430
|
def execute(&block)
|
429
431
|
return self.result if result
|
430
|
-
raise CouchRest::Model::DatabaseNotDefined if
|
432
|
+
raise CouchRest::Model::DatabaseNotDefined if database.nil?
|
431
433
|
|
432
434
|
# Remove the reduce value if its not needed to prevent CouchDB errors
|
433
435
|
query.delete(:reduce) unless can_reduce?
|
434
436
|
|
435
|
-
design_doc.sync(
|
437
|
+
design_doc.sync(database)
|
436
438
|
|
437
|
-
self.result = design_doc.view_on(
|
439
|
+
self.result = design_doc.view_on(database, name, query, &block)
|
438
440
|
end
|
439
441
|
|
440
442
|
# Class Methods
|
@@ -492,8 +494,16 @@ module CouchRest
|
|
492
494
|
raise "View cannot be created without recognised name, :map or :by options" if opts[:by].nil?
|
493
495
|
|
494
496
|
# convert emit symbols to properties
|
495
|
-
|
496
|
-
|
497
|
+
emits, emit_guards = if opts[:emit].is_a? Symbol
|
498
|
+
[["doc['#{opts[:emit]}']"], ["doc['#{opts[:emit]}']"]]
|
499
|
+
elsif opts[:emit].is_a? Array
|
500
|
+
[
|
501
|
+
opts[:emit].map { |i| i.is_a?(Symbol) ? "doc['#{i}']" : i },
|
502
|
+
opts[:emit].map { |i| i.is_a?(Symbol) ? "doc['#{i}']" : nil}.compact
|
503
|
+
]
|
504
|
+
else
|
505
|
+
[[opts[:emit] || 1], nil]
|
506
|
+
end
|
497
507
|
|
498
508
|
opts[:allow_blank] = opts[:allow_blank].nil? ? true : opts[:allow_blank]
|
499
509
|
opts[:guards] ||= []
|
@@ -501,9 +511,11 @@ module CouchRest
|
|
501
511
|
|
502
512
|
keys = opts[:by].map{|o| "doc['#{o}']"}
|
503
513
|
emit_keys = keys.length == 1 ? keys.first : "[#{keys.join(', ')}]"
|
504
|
-
emit_value =
|
514
|
+
emit_value = emits.length == 1 ? emits.first : "[#{emits.join(', ')}]"
|
505
515
|
opts[:guards] += keys.map{|k| "(#{k} != null)"} unless opts[:allow_nil]
|
506
516
|
opts[:guards] += keys.map{|k| "(#{k} != '')"} unless opts[:allow_blank]
|
517
|
+
opts[:guards] += emit_guards.map{|k| "(#{k} != null)"} unless emit_guards.nil? || opts[:allow_nil]
|
518
|
+
opts[:guards] += emit_guards.map{|k| "(#{k} != '')"} unless emit_guards.nil? || opts[:allow_blank]
|
507
519
|
opts[:map] = <<-EOF
|
508
520
|
function(doc) {
|
509
521
|
if (#{opts[:guards].join(' && ')}) {
|
@@ -511,7 +523,7 @@ module CouchRest
|
|
511
523
|
}
|
512
524
|
}
|
513
525
|
EOF
|
514
|
-
if opts[:reduce].nil?
|
526
|
+
if opts[:reduce].nil? && emit_guards.nil?
|
515
527
|
# Use built-in sum function by default
|
516
528
|
opts[:reduce] = "_sum"
|
517
529
|
end
|
@@ -552,10 +564,15 @@ module CouchRest
|
|
552
564
|
# A special wrapper class that provides easy access to the key
|
553
565
|
# fields in a result row.
|
554
566
|
class ViewRow < Hash
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
567
|
+
|
568
|
+
# Owner will either be the original model, or a proxy and must respond
|
569
|
+
# to `#build_from_database` and `#get` calls.
|
570
|
+
# The owner is responsible for setting the correct database on instantiation,
|
571
|
+
# if required.
|
572
|
+
attr_reader :owner
|
573
|
+
|
574
|
+
def initialize(hash, owner)
|
575
|
+
@owner = owner
|
559
576
|
replace(hash)
|
560
577
|
end
|
561
578
|
def id
|
@@ -575,12 +592,10 @@ module CouchRest
|
|
575
592
|
def doc
|
576
593
|
@doc ||= begin
|
577
594
|
if self['doc']
|
578
|
-
|
579
|
-
obj.database ||= db
|
580
|
-
obj
|
595
|
+
owner.build_from_database(self['doc'])
|
581
596
|
else
|
582
597
|
doc_id = (value.is_a?(Hash) && value['_id']) ? value['_id'] : self.id
|
583
|
-
doc_id ?
|
598
|
+
doc_id ? owner.get(doc_id) : nil
|
584
599
|
end
|
585
600
|
end
|
586
601
|
end
|