dock 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,15 @@
1
+ .gem
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dock.gemspec
4
+ gemspec
@@ -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.
@@ -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
+ ```
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -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
@@ -0,0 +1,12 @@
1
+ require_relative "dock/version"
2
+
3
+ module Dock
4
+ # A collection of registered adapters
5
+ def self.adapters
6
+ @@adapters ||= []
7
+ end
8
+ end
9
+
10
+ require_relative "dock/base"
11
+ require_relative "dock/env"
12
+ require_relative "dock/aliases"
@@ -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