dock 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +89 -0
- data/Rakefile +2 -0
- data/dock.gemspec +35 -0
- data/lib/dock.rb +12 -0
- data/lib/dock/adapters/active_record.rb +117 -0
- data/lib/dock/adapters/cequel.rb +124 -0
- data/lib/dock/adapters/couchbase.rb +177 -0
- data/lib/dock/adapters/couchdb.rb +73 -0
- data/lib/dock/adapters/datamapper.rb +88 -0
- data/lib/dock/adapters/mongoid.rb +98 -0
- data/lib/dock/adapters/mongomapper.rb +91 -0
- data/lib/dock/adapters/nobrainer.rb +81 -0
- data/lib/dock/adapters/sequel.rb +127 -0
- data/lib/dock/adapters/sinatra_ar.rb +119 -0
- data/lib/dock/aliases.rb +13 -0
- data/lib/dock/base.rb +80 -0
- data/lib/dock/env.rb +43 -0
- data/lib/dock/version.rb +3 -0
- data/spec/dock/adapters/activerecord_spec.rb +0 -0
- data/spec/dock/adapters/cequel_spec.rb +0 -0
- data/spec/dock/adapters/couchbase_spec.rb +0 -0
- data/spec/dock/adapters/couchdb_spec.rb +0 -0
- data/spec/dock/adapters/datamapper_spec.rb +0 -0
- data/spec/dock/adapters/mongoid_spec.rb +0 -0
- data/spec/dock/adapters/mongomapper_spec.rb +0 -0
- data/spec/dock/adapters/nobrainer_spec.rb +0 -0
- data/spec/dock/adapters/sequel_spec.rb +0 -0
- data/spec/dock/adapters/sinatra_ar_spec.rb +0 -0
- data/spec/dock/base_spec.rb +0 -0
- data/spec/dock/example_app.rb +0 -0
- data/spec/dock_spec.rb +12 -0
- data/spec/spec_helper.rb +13 -0
- metadata +261 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a3eb11e2ae87a5336e40dd098eb5371c31ce95ab
|
4
|
+
data.tar.gz: f1fce866bc3e9b71c24de364bfcd61630fb822f2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5bc60d26a3ad01791831fb2615a275bf5968aac8e14e9bb0d689ed99518afe29ab92338dc1cfd4c5c96e784b841a20fa9a04b9fa7a2cf372213b9c8bdc24c7d0
|
7
|
+
data.tar.gz: d84f663d14fbdc13046d3a7377c5a8da48ed8790f070c0053a04cb9b6e4e38e7a93cb675f5d156ed82fdd5e97dd723cae29c2dca4b06da6335727a9f269c483d
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Austin Vecchio
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# dock
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
dock is anything but simple. This gem outlines what the [ORM Adapter](https://github.com/ianwhite/orm_adapter) should have been in terms of both methods and database support.
|
5
|
+
|
6
|
+
## Support
|
7
|
+
|
8
|
+
|
9
|
+
#### NOTE:
|
10
|
+
Support may be dropped for datamapper and sinatra activerecord since the last update for these gems has been a while.
|
11
|
+
The fraction shows the number of methods supported out of the total number of methods for dock all together for that adapter.
|
12
|
+
|
13
|
+
- 16/20 [ActiveRecord](http://guides.rubyonrails.org/active_record_basics.html)
|
14
|
+
- 16/20 [Sinatra ActiveRecord](https://github.com/janko-m/sinatra-activerecord)
|
15
|
+
- 16/20 [CouchBase](https://github.com/couchbase/couchbase-ruby-model)
|
16
|
+
- 0/20 [CouchDB](http://couchdb.apache.org/)
|
17
|
+
- 16/20 [Cequel](https://github.com/cequel/cequel)
|
18
|
+
- 16/20 [Datamapper](https://github.com/datamapper/dm-core)
|
19
|
+
- 16/20 [MongoMapper](http://mongomapper.com/)
|
20
|
+
- 16/20 [Mongoid](http://mongoid.org/en/mongoid/index.html)
|
21
|
+
- 16/20 [NoBrainer](http://nobrainer.io/)
|
22
|
+
- 16/20 [Sequel](https://github.com/jeremyevans/sequel)
|
23
|
+
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
Add this line to your application's Gemfile:
|
28
|
+
|
29
|
+
Note: until I can get the other dock removed, or change the name of this gem, this will be the only way to install this gem.
|
30
|
+
```ruby
|
31
|
+
gem 'dock', :git => 'git://github.com/avecchio/dock.git'
|
32
|
+
```
|
33
|
+
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
$ bundle
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
$ gem install dock
|
41
|
+
|
42
|
+
## Contributing
|
43
|
+
|
44
|
+
WARNING: There are either methods missing in certain adapters, or other methdos that run on broken or untested code. So this gem is neither complete nor operational at the time being and will take some time to develop. Thus contributions are welcomed as well as additional adapters, methods and test code. But be warned, if you add a method to one adapter, you must create the same method for the rest of the adapters conforming to that adapters mechanics.
|
45
|
+
|
46
|
+
1. Fork it ( https://github.com/[my-github-username]/dock/fork )
|
47
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
48
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
49
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
50
|
+
5. Create a new Pull Request
|
51
|
+
|
52
|
+
#### Goals
|
53
|
+
|
54
|
+
1. Tests need to be written
|
55
|
+
2. Methods to all adapters need to be checked and verified and possibly re-written.
|
56
|
+
3. Documentation!!
|
57
|
+
|
58
|
+
## Usage
|
59
|
+
|
60
|
+
#### Getting Started
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
require 'dock'
|
64
|
+
```
|
65
|
+
|
66
|
+
#### Methods
|
67
|
+
|
68
|
+
```
|
69
|
+
user_model.create #
|
70
|
+
user_model.find #
|
71
|
+
user_model.find! #
|
72
|
+
user_model.all #
|
73
|
+
user_model.first #
|
74
|
+
user_model.id #
|
75
|
+
user_model.update #
|
76
|
+
user_model.destroy #
|
77
|
+
user_model.associations #
|
78
|
+
user_model.model_name #
|
79
|
+
user_model.column_names #
|
80
|
+
user_model.count # Count the number of results returned from the 'all' method
|
81
|
+
user_model.encoding #
|
82
|
+
user_model.belongs_to #
|
83
|
+
user_model.has_many #
|
84
|
+
user_model.scoped #
|
85
|
+
user_model.embedded #
|
86
|
+
user_model.cyclic? #
|
87
|
+
user_model.supports_joins? #
|
88
|
+
user_model.properties #
|
89
|
+
```
|
data/Rakefile
ADDED
data/dock.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dock/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dock"
|
8
|
+
spec.version = Dock::VERSION
|
9
|
+
spec.authors = ["Austin Vecchio"]
|
10
|
+
spec.email = ["au.vecchio@gmail.com"]
|
11
|
+
spec.summary = %q{What Orm Adapter should have been}
|
12
|
+
spec.description = %q{Twenty methods for ten different adapters}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
24
|
+
# All supported models
|
25
|
+
spec.add_development_dependency "activerecord", "~> 4.1"
|
26
|
+
spec.add_development_dependency "cequel", "~> 1.4"
|
27
|
+
#spec.add_development_dependency "couchbase"#, "~>"
|
28
|
+
spec.add_development_dependency "couchrest", "~> 1.2"
|
29
|
+
spec.add_development_dependency "datamapper", "~> 1.2"
|
30
|
+
spec.add_development_dependency "mongoid", "~> 4.0"
|
31
|
+
spec.add_development_dependency "mongo_mapper", "~> 0.8"
|
32
|
+
spec.add_development_dependency "nobrainer", "~> 0.16"
|
33
|
+
spec.add_development_dependency "sequel", "~> 4.14"
|
34
|
+
spec.add_development_dependency "sinatra-activerecord", "~> 2.0"
|
35
|
+
end
|
data/lib/dock.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module Dock
|
4
|
+
class ActiveRecord < Base
|
5
|
+
# Checked
|
6
|
+
def create(attributes = {})
|
7
|
+
model.create!(attributes)
|
8
|
+
end
|
9
|
+
# Checked
|
10
|
+
def find(id)
|
11
|
+
model.find(wrap_key(id))
|
12
|
+
end
|
13
|
+
# Checked
|
14
|
+
def find!(id)
|
15
|
+
model.where(model.primary_key => wrap_key(id)).first
|
16
|
+
end
|
17
|
+
# Checked
|
18
|
+
def all(options = {})
|
19
|
+
construct_relation(model, options)
|
20
|
+
end
|
21
|
+
# Checked
|
22
|
+
def first(options = {})
|
23
|
+
construct_relation(model, options).first
|
24
|
+
end
|
25
|
+
# Checked
|
26
|
+
def id
|
27
|
+
model.id
|
28
|
+
end
|
29
|
+
# Checked
|
30
|
+
def update(search_key, find_by, update_key, by_value)
|
31
|
+
entry = model.find_by(search_key find_by)
|
32
|
+
entry.update(update_key by_value)
|
33
|
+
end
|
34
|
+
# Checked
|
35
|
+
def destroy(object)
|
36
|
+
object.destroy && true if valid_object?(object)
|
37
|
+
end
|
38
|
+
def associations()
|
39
|
+
|
40
|
+
end
|
41
|
+
# Checked
|
42
|
+
def model_name
|
43
|
+
model.model_name
|
44
|
+
end
|
45
|
+
# Checked
|
46
|
+
def column_names
|
47
|
+
model.column_names
|
48
|
+
end
|
49
|
+
# Checked
|
50
|
+
def count(options = {})
|
51
|
+
all(options).count
|
52
|
+
end
|
53
|
+
# Checked
|
54
|
+
def encoding
|
55
|
+
model.client_encoding()
|
56
|
+
end
|
57
|
+
def belongs_to()
|
58
|
+
|
59
|
+
end
|
60
|
+
def has_many()
|
61
|
+
|
62
|
+
end
|
63
|
+
# Checked
|
64
|
+
def scoped?
|
65
|
+
model.all
|
66
|
+
end
|
67
|
+
# Checked
|
68
|
+
def embedded?
|
69
|
+
false
|
70
|
+
end
|
71
|
+
# Checked
|
72
|
+
def cyclic?
|
73
|
+
false
|
74
|
+
end
|
75
|
+
# Checked
|
76
|
+
def supports_joins?
|
77
|
+
true
|
78
|
+
end
|
79
|
+
def properties()
|
80
|
+
|
81
|
+
end
|
82
|
+
protected
|
83
|
+
def construct_relation(relation, options)
|
84
|
+
conditions, order, limit, offset = extract_conditions!(options)
|
85
|
+
|
86
|
+
relation = relation.where(conditions_to_fields(conditions))
|
87
|
+
relation = relation.order(order_clause(order)) if order.any?
|
88
|
+
relation = relation.limit(limit) if limit
|
89
|
+
relation = relation.offset(offset) if offset
|
90
|
+
|
91
|
+
relation
|
92
|
+
end
|
93
|
+
|
94
|
+
# Introspects the model to convert and objects in conditions into foreign key and type fields
|
95
|
+
def conditions_to_fields(conditions)
|
96
|
+
fields = {}
|
97
|
+
conditions.each do |key, value|
|
98
|
+
if value.is_a?(::ActiveRecord::Base) && (assoc = model.reflect_on_association(key.to_sym)) && assoc.belongs_to?
|
99
|
+
if ::ActiveRecord::VERSION::STRING < "3.1"
|
100
|
+
fields[assoc.primary_key_name] = value.send(value.class.primary_key)
|
101
|
+
fields[assoc.options[:foreign_type]] = value.class.base_class.name.to_s if assoc.options[:polymorphic]
|
102
|
+
else # >= 3.1
|
103
|
+
fields[assoc.foreign_key] = value.send(value.class.primary_key)
|
104
|
+
fields[assoc.foreign_type] = value.class.base_class.name.to_s if assoc.options[:polymorphic]
|
105
|
+
end
|
106
|
+
else
|
107
|
+
fields[key] = value
|
108
|
+
end
|
109
|
+
fields
|
110
|
+
end
|
111
|
+
|
112
|
+
def order_clause(order)
|
113
|
+
order.map {|pair| "#{pair[0]} #{pair[1]}"}.join(",")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'cequel'
|
2
|
+
|
3
|
+
module Dock
|
4
|
+
class Cequel < Base
|
5
|
+
def create(attributes = {})
|
6
|
+
model.create(attributes)
|
7
|
+
end
|
8
|
+
def find(key_values)
|
9
|
+
find!(key_values)
|
10
|
+
rescue Cequel::Record::RecordNotFound
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
def find!(key_values)
|
14
|
+
model.find(*key_values)
|
15
|
+
end
|
16
|
+
def all(options = {})
|
17
|
+
construct_scope(options).to_a
|
18
|
+
end
|
19
|
+
def first(options = {})
|
20
|
+
construct_scope(options).first
|
21
|
+
end
|
22
|
+
def id
|
23
|
+
'id'
|
24
|
+
end
|
25
|
+
def update(search_key, find_by, update_key, by_value)
|
26
|
+
entry = model.find(update_key).posts.find(find_by)
|
27
|
+
entry.update_attributes!(update_key by_value)
|
28
|
+
end
|
29
|
+
def destroy(record)
|
30
|
+
record.destroy
|
31
|
+
end
|
32
|
+
def associations()
|
33
|
+
|
34
|
+
end
|
35
|
+
def model_name
|
36
|
+
model.class.name
|
37
|
+
end
|
38
|
+
def column_names
|
39
|
+
model.columns.map { |column| column.name }
|
40
|
+
end
|
41
|
+
# Checked
|
42
|
+
def count(options = {})
|
43
|
+
all(options).count
|
44
|
+
end
|
45
|
+
def encoding
|
46
|
+
'UTF-8'
|
47
|
+
end
|
48
|
+
def belongs_to()
|
49
|
+
|
50
|
+
end
|
51
|
+
def has_many()
|
52
|
+
|
53
|
+
end
|
54
|
+
def scoped?
|
55
|
+
false
|
56
|
+
end
|
57
|
+
def embedded?
|
58
|
+
false
|
59
|
+
end
|
60
|
+
def cyclic?
|
61
|
+
false
|
62
|
+
end
|
63
|
+
def supports_joins?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
def properties()
|
67
|
+
|
68
|
+
end
|
69
|
+
private
|
70
|
+
def construct_scope(options)
|
71
|
+
conditions, _, limit, _ =
|
72
|
+
extract_conditions!(options.deep_symbolize_keys)
|
73
|
+
scope = model.all
|
74
|
+
scope = apply_secondary_index_scope(scope, conditions) ||
|
75
|
+
apply_primary_key_scope(scope, conditions)
|
76
|
+
scope = scope.limit(limit) if limit
|
77
|
+
scope
|
78
|
+
end
|
79
|
+
|
80
|
+
def extract_conditions!(options)
|
81
|
+
super.tap do |_, order, _, offset|
|
82
|
+
if order.present?
|
83
|
+
fail ArgumentError,
|
84
|
+
"Cassandra does not support ordering of results by " \
|
85
|
+
"arbitrary columns"
|
86
|
+
end
|
87
|
+
if offset.present?
|
88
|
+
fail ArgumentError, 'Cassandra does not support row offsets'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def apply_primary_key_scope(scope, conditions)
|
94
|
+
conditions = conditions.dup
|
95
|
+
conditions.assert_valid_keys(*model.key_column_names)
|
96
|
+
|
97
|
+
model.key_column_names.each do |column_name|
|
98
|
+
column_value = conditions.delete(column_name)
|
99
|
+
break unless column_value
|
100
|
+
scope = scope[column_value]
|
101
|
+
end
|
102
|
+
|
103
|
+
assert_conditions_empty!(conditions)
|
104
|
+
|
105
|
+
scope
|
106
|
+
end
|
107
|
+
|
108
|
+
def apply_secondary_index_scope(scope, conditions)
|
109
|
+
return unless conditions.one?
|
110
|
+
condition_column = model.reflect_on_column(conditions.keys.first)
|
111
|
+
if condition_column.data_column? && condition_column.indexed?
|
112
|
+
scope.where(*conditions.first)
|
113
|
+
else
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def assert_conditions_empty!(conditions)
|
118
|
+
unless conditions.empty?
|
119
|
+
fail ArgumentError,
|
120
|
+
"Invalid columns for conditions: #{conditions.keys.join(', ')}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'couchbase'
|
2
|
+
|
3
|
+
module Dock
|
4
|
+
class Couchbase < Base
|
5
|
+
def create(attributes = {})
|
6
|
+
model.create!(attributes)
|
7
|
+
end
|
8
|
+
def find(id)
|
9
|
+
model.find wrap_key(id)
|
10
|
+
end
|
11
|
+
def find!(id)
|
12
|
+
model.find_by_id(wrap_key(id))
|
13
|
+
end
|
14
|
+
def all(options = {})
|
15
|
+
view_name, view_options, options = view_for_options(options)
|
16
|
+
conditions, order, limit, offset = extract_conditions!(options)
|
17
|
+
stream = model.send(view_name, view_options)
|
18
|
+
# deal with everything which wasn't handled via the view
|
19
|
+
stream = apply_conditions(stream, conditions)
|
20
|
+
stream = apply_order(stream, order)
|
21
|
+
stream = stream.drop(offset) if offset
|
22
|
+
stream = stream.take(limit) if limit
|
23
|
+
stream.to_a # make sure to return an array
|
24
|
+
end
|
25
|
+
def first(options = {})
|
26
|
+
id = options.delete(:id)
|
27
|
+
conditions, _ = extract_conditions!(options.dup)
|
28
|
+
if id
|
29
|
+
apply_conditions([get(id)], conditions).first
|
30
|
+
else
|
31
|
+
find_all(options).first
|
32
|
+
end
|
33
|
+
end
|
34
|
+
def id
|
35
|
+
model.id
|
36
|
+
end
|
37
|
+
def update(search_key=:id, find_by, update_key, by_value)
|
38
|
+
entry = model.find(find_by)
|
39
|
+
entry.update(update_key => by_value)
|
40
|
+
entry.save
|
41
|
+
end
|
42
|
+
def destroy(object)
|
43
|
+
object.destroy if valid_object?(object)
|
44
|
+
end
|
45
|
+
def associations()
|
46
|
+
|
47
|
+
end
|
48
|
+
def model_name()
|
49
|
+
model.class.name
|
50
|
+
end
|
51
|
+
def column_names()
|
52
|
+
model.properties.map(&:name)
|
53
|
+
end
|
54
|
+
# Checked
|
55
|
+
def count(options = {})
|
56
|
+
all(options).count
|
57
|
+
end
|
58
|
+
def encoding
|
59
|
+
'UTF-8'
|
60
|
+
end
|
61
|
+
def belongs_to()
|
62
|
+
|
63
|
+
end
|
64
|
+
def has_many()
|
65
|
+
|
66
|
+
end
|
67
|
+
def scoped?
|
68
|
+
false
|
69
|
+
end
|
70
|
+
def embedded?
|
71
|
+
false
|
72
|
+
end
|
73
|
+
def cyclic?
|
74
|
+
false
|
75
|
+
end
|
76
|
+
def supports_joins?
|
77
|
+
false
|
78
|
+
end
|
79
|
+
def properties()
|
80
|
+
|
81
|
+
end
|
82
|
+
private
|
83
|
+
def apply_conditions(stream, conditions)
|
84
|
+
return stream if conditions.empty?
|
85
|
+
stream.select { |item| satisfies_conditions? item, conditions }
|
86
|
+
end
|
87
|
+
|
88
|
+
def satisfies_conditions?(item, conditions)
|
89
|
+
conditions.all? { |field, value| item.send(field) == value }
|
90
|
+
end
|
91
|
+
|
92
|
+
def apply_order(stream, order)
|
93
|
+
return stream if order.empty?
|
94
|
+
|
95
|
+
stream.to_a.sort_by do |item|
|
96
|
+
sort = []
|
97
|
+
order = order.to_enum
|
98
|
+
o = order.next
|
99
|
+
loop do
|
100
|
+
case o
|
101
|
+
when Array
|
102
|
+
value = item.send(o[0])
|
103
|
+
value = invert_value(value) if o[1] == :desc
|
104
|
+
sort.push(value)
|
105
|
+
else
|
106
|
+
value = item.send(o[0])
|
107
|
+
case order.peek
|
108
|
+
when :asc
|
109
|
+
begin
|
110
|
+
order.next
|
111
|
+
rescue StopIteration
|
112
|
+
break
|
113
|
+
end
|
114
|
+
when :desc
|
115
|
+
value = invert_value(value)
|
116
|
+
begin
|
117
|
+
order.next
|
118
|
+
rescue StopIteration
|
119
|
+
break
|
120
|
+
end
|
121
|
+
end
|
122
|
+
sort.push(value)
|
123
|
+
end
|
124
|
+
begin
|
125
|
+
o = order.next
|
126
|
+
rescue StopIteration
|
127
|
+
break
|
128
|
+
end
|
129
|
+
end
|
130
|
+
sort
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def invert_value(value)
|
135
|
+
case value
|
136
|
+
when String
|
137
|
+
inverse = []
|
138
|
+
value.each_codepoint { |c| inverse.push(-c) }
|
139
|
+
inverse
|
140
|
+
else
|
141
|
+
-value
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def view_for_options(options)
|
146
|
+
view_name = :all
|
147
|
+
view_options = { :stale => false }
|
148
|
+
conditions, order, limit, offset = extract_conditions!(options.dup)
|
149
|
+
|
150
|
+
# TODO would be nice to merge multiple conditions into one view name
|
151
|
+
# for example users have a rating, and the comprised key is [user,
|
152
|
+
# rating] if the view is named "by_user_and_rating" we could then merge
|
153
|
+
# this into one and even apply the ordering in one go
|
154
|
+
remaining_conditions = conditions.reject { |condition, value|
|
155
|
+
if klass.respond_to?("by_#{condition}")
|
156
|
+
view_name = "by_#{condition}".to_sym
|
157
|
+
view_options[:key] = value
|
158
|
+
end
|
159
|
+
}
|
160
|
+
|
161
|
+
options = { :conditions => remaining_conditions, :order => order }
|
162
|
+
|
163
|
+
if remaining_conditions.empty?
|
164
|
+
# merge limit, and offset conditions into view query
|
165
|
+
view_options[:limit] = limit if limit
|
166
|
+
view_options[:skip] = offset if offset
|
167
|
+
else
|
168
|
+
options[:limit] = limit if limit
|
169
|
+
options[:offset] = offset if offset
|
170
|
+
end
|
171
|
+
|
172
|
+
raise MissingViewException.new(view_name) unless klass.respond_to?(view_name)
|
173
|
+
|
174
|
+
[view_name, view_options, options]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|