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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dc3de5182b5c551856bd3dbbbdea62fe97feccf8
4
- data.tar.gz: 1aac104a38f10500bcfbf6d3812442b7fa6ca677
3
+ metadata.gz: c9da5f0b0e14df586c9cb3c85dea4f0b7de7263b
4
+ data.tar.gz: c921fb6038d169cc018f2144e7f64b233bedfd4f
5
5
  SHA512:
6
- metadata.gz: f5c34608cb902751b5671abc660a23203cd7f340fcc05eefc670be5859f7693bb482bf05c400fd5789abfdd09affd9379ecc6589924b5ac70805a05fc0b81421
7
- data.tar.gz: 39b5d65f53d8cb283f86fbfa0a3d6c27edea311dede32422cce4a0225cc42f98f2ed672cd65e01f48d176cc18a031f2758bbb12011f5391f7f57800ea88bcd80
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
@@ -0,0 +1,11 @@
1
+ FROM ruby:2.3
2
+
3
+ ENV WORK_DIR /usr/lib/couchrest_model
4
+
5
+ RUN mkdir -p $WORK_DIR
6
+ WORKDIR $WORK_DIR
7
+
8
+ COPY . $WORK_DIR
9
+
10
+ RUN bundle install --jobs=3 --retry=3
11
+
data/Gemfile CHANGED
@@ -2,5 +2,7 @@
2
2
  source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
+ gem "guard-rspec", "~> 4.7.0", group: :test
6
+
5
7
  # Enable for testing against local couchrest
6
8
  # gem "couchrest", path: "/Users/sam/workspace/couchrest"
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.beta1
1
+ 2.2.0.beta2
@@ -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.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")
@@ -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.beta1 - pending
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 normal use_database method so that a database
12
+ # Overwrite the CouchRest::Document.use_database method so that a database
13
13
  # name can be provided instead of a full connection.
14
- # The actual database will be validated when it is requested for use.
15
- # Note that this should not be used with proxied models!
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
- @_use_database = db
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, in which
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 ||= CouchRest::Server.new(prepare_server_uri, :persistent => connection_configuration[:persistent])
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
- conf = connection_configuration
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.update(
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
- connection_config_cache[file] ||=
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
@@ -46,6 +46,9 @@ module CouchRest
46
46
  id = self['_id']
47
47
 
48
48
  if !doc
49
+ # make sure the checksum has been calculated
50
+ checksum! if !self['couchrest-hash']
51
+
49
52
  # no need to migrate, just save it
50
53
  new_doc = to_hash.dup
51
54
  db.save_doc(new_doc)
@@ -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
- # Extrace important non-regular query values
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.model = (proxy || parent)
31
- self.owner = parent
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.model = (proxy || parent.model)
37
- self.owner = parent.owner
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, model, use_database)
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, model, use_database)}
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(owner.default_per_page).skip(owner.default_per_page * ([page.to_i, 1].max - 1))
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 use_database.nil?
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(use_database)
437
+ design_doc.sync(database)
436
438
 
437
- self.result = design_doc.view_on(use_database, name, query, &block)
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
- opts[:emit] = "doc['#{opts[:emit]}']" if opts[:emit].is_a?(Symbol)
496
- opts[:emit] = "[" + opts[:emit].map { |i| i.is_a?(Symbol) ? "doc['#{i}']" : i }.join(', ') + "]" if opts[:emit].is_a?(Array)
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 = opts[:emit] || 1;
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
- attr_reader :model, :db
556
- def initialize(hash, model, db = nil)
557
- @model = model
558
- @db = db || model.database
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
- obj = model.build_from_database(self['doc'])
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 ? model.get(doc_id, db) : nil
598
+ doc_id ? owner.get(doc_id) : nil
584
599
  end
585
600
  end
586
601
  end