couchrest_model 2.2.0.beta1 → 2.2.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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