dm-aggregates 0.9.11 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{History.txt → History.rdoc} +4 -0
- data/Manifest.txt +4 -3
- data/{README.txt → README.rdoc} +0 -0
- data/Rakefile +2 -3
- data/lib/dm-aggregates/adapters/data_objects_adapter.rb +67 -27
- data/lib/dm-aggregates/aggregate_functions.rb +184 -181
- data/lib/dm-aggregates/collection.rb +10 -8
- data/lib/dm-aggregates/core_ext/symbol.rb +9 -0
- data/lib/dm-aggregates/model.rb +10 -8
- data/lib/dm-aggregates/query.rb +27 -0
- data/lib/dm-aggregates/repository.rb +5 -3
- data/lib/dm-aggregates/version.rb +1 -1
- data/lib/dm-aggregates.rb +22 -11
- data/spec/public/collection_spec.rb +1 -2
- data/spec/public/model_spec.rb +1 -2
- data/spec/public/shared/aggregate_shared_spec.rb +1 -1
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +11 -4
- data/tasks/install.rb +1 -1
- data/tasks/spec.rb +4 -4
- metadata +16 -22
- data/lib/dm-aggregates/support/symbol.rb +0 -21
data/Manifest.txt
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
-
History.
|
1
|
+
History.rdoc
|
2
2
|
LICENSE
|
3
3
|
Manifest.txt
|
4
|
-
README.
|
4
|
+
README.rdoc
|
5
5
|
Rakefile
|
6
6
|
TODO
|
7
7
|
lib/dm-aggregates.rb
|
8
8
|
lib/dm-aggregates/adapters/data_objects_adapter.rb
|
9
9
|
lib/dm-aggregates/aggregate_functions.rb
|
10
10
|
lib/dm-aggregates/collection.rb
|
11
|
+
lib/dm-aggregates/core_ext/symbol.rb
|
11
12
|
lib/dm-aggregates/model.rb
|
13
|
+
lib/dm-aggregates/query.rb
|
12
14
|
lib/dm-aggregates/repository.rb
|
13
|
-
lib/dm-aggregates/support/symbol.rb
|
14
15
|
lib/dm-aggregates/version.rb
|
15
16
|
spec/public/collection_spec.rb
|
16
17
|
spec/public/model_spec.rb
|
data/{README.txt → README.rdoc}
RENAMED
File without changes
|
data/Rakefile
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
require 'rubygems'
|
3
2
|
|
4
3
|
ROOT = Pathname(__FILE__).dirname.expand_path
|
5
4
|
JRUBY = RUBY_PLATFORM =~ /java/
|
@@ -14,10 +13,10 @@ GEM_NAME = 'dm-aggregates'
|
|
14
13
|
GEM_VERSION = DataMapper::Aggregates::VERSION
|
15
14
|
GEM_DEPENDENCIES = [['dm-core', GEM_VERSION]]
|
16
15
|
GEM_CLEAN = %w[ log pkg coverage ]
|
17
|
-
GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.
|
16
|
+
GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.rdoc LICENSE TODO History.rdoc ] }
|
18
17
|
|
19
18
|
PROJECT_NAME = 'datamapper'
|
20
|
-
PROJECT_URL = "http://github.com/
|
19
|
+
PROJECT_URL = "http://github.com/datamapper/dm-more/tree/master/#{GEM_NAME}"
|
21
20
|
PROJECT_DESCRIPTION = PROJECT_SUMMARY = 'DataMapper plugin providing support for aggregates, functions on collections and datasets'
|
22
21
|
|
23
22
|
[ ROOT, ROOT.parent ].each do |dir|
|
@@ -1,24 +1,44 @@
|
|
1
1
|
module DataMapper
|
2
|
-
module
|
3
|
-
|
2
|
+
module Aggregates
|
3
|
+
module DataObjectsAdapter
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, SQL)
|
6
|
+
end
|
7
|
+
|
4
8
|
def aggregate(query)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
fields = query.fields
|
10
|
+
types = fields.map { |p| p.respond_to?(:operator) ? String : p.primitive }
|
11
|
+
|
12
|
+
field_size = fields.size
|
13
|
+
|
14
|
+
records = []
|
15
|
+
|
16
|
+
with_connection do |connection|
|
17
|
+
statement, bind_values = select_statement(query)
|
18
|
+
|
19
|
+
command = connection.create_command(statement)
|
20
|
+
command.set_types(types)
|
21
|
+
|
22
|
+
reader = command.execute_reader(*bind_values)
|
23
|
+
|
24
|
+
begin
|
25
|
+
while(reader.next!)
|
26
|
+
row = fields.zip(reader.values).map do |field, value|
|
27
|
+
if field.respond_to?(:operator)
|
28
|
+
send(field.operator, field.target, value)
|
29
|
+
else
|
30
|
+
field.typecast(value)
|
31
|
+
end
|
14
32
|
end
|
15
|
-
end
|
16
33
|
|
17
|
-
|
34
|
+
records << (field_size > 1 ? row : row[0])
|
35
|
+
end
|
36
|
+
ensure
|
37
|
+
reader.close
|
18
38
|
end
|
19
|
-
|
20
|
-
results
|
21
39
|
end
|
40
|
+
|
41
|
+
records
|
22
42
|
end
|
23
43
|
|
24
44
|
private
|
@@ -44,26 +64,32 @@ module DataMapper
|
|
44
64
|
end
|
45
65
|
|
46
66
|
module SQL
|
47
|
-
|
48
|
-
|
49
|
-
|
67
|
+
def self.included(base)
|
68
|
+
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
69
|
+
# FIXME: figure out a cleaner approach than AMC
|
70
|
+
alias property_to_column_name_without_operator property_to_column_name
|
71
|
+
alias property_to_column_name property_to_column_name_with_operator
|
72
|
+
RUBY
|
73
|
+
end
|
50
74
|
|
51
|
-
def
|
75
|
+
def property_to_column_name_with_operator(property, qualify)
|
52
76
|
case property
|
53
|
-
when Query::Operator
|
54
|
-
aggregate_field_statement(
|
55
|
-
|
56
|
-
|
77
|
+
when DataMapper::Query::Operator
|
78
|
+
aggregate_field_statement(property.operator, property.target, qualify)
|
79
|
+
|
80
|
+
when Property, DataMapper::Query::Path
|
81
|
+
property_to_column_name_without_operator(property, qualify)
|
82
|
+
|
57
83
|
else
|
58
84
|
raise ArgumentError, "+property+ must be a DataMapper::Query::Operator, a DataMapper::Property or a Query::Path, but was a #{property.class} (#{property.inspect})"
|
59
85
|
end
|
60
86
|
end
|
61
87
|
|
62
|
-
def aggregate_field_statement(
|
88
|
+
def aggregate_field_statement(aggregate_function, property, qualify)
|
63
89
|
column_name = if aggregate_function == :count && property == :all
|
64
90
|
'*'
|
65
91
|
else
|
66
|
-
property_to_column_name(
|
92
|
+
property_to_column_name(property, qualify)
|
67
93
|
end
|
68
94
|
|
69
95
|
function_name = case aggregate_function
|
@@ -78,8 +104,22 @@ module DataMapper
|
|
78
104
|
"#{function_name}(#{column_name})"
|
79
105
|
end
|
80
106
|
end # module SQL
|
81
|
-
|
82
|
-
include SQL
|
83
107
|
end # class DataObjectsAdapter
|
108
|
+
end # module Aggregates
|
109
|
+
|
110
|
+
module Adapters
|
111
|
+
extendable do
|
112
|
+
|
113
|
+
# TODO: document
|
114
|
+
# @api private
|
115
|
+
def const_added(const_name)
|
116
|
+
if DataMapper::Aggregates.const_defined?(const_name)
|
117
|
+
adapter = const_get(const_name)
|
118
|
+
adapter.send(:include, DataMapper::Aggregates.const_get(const_name))
|
119
|
+
end
|
120
|
+
|
121
|
+
super
|
122
|
+
end
|
123
|
+
end
|
84
124
|
end # module Adapters
|
85
125
|
end # module DataMapper
|
@@ -1,200 +1,203 @@
|
|
1
1
|
module DataMapper
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
2
|
+
module Aggregates
|
3
|
+
module Functions
|
4
|
+
# Count results (given the conditions)
|
5
|
+
#
|
6
|
+
# @example the count of all friends
|
7
|
+
# Friend.count
|
8
|
+
#
|
9
|
+
# @example the count of all friends older then 18
|
10
|
+
# Friend.count(:age.gt => 18)
|
11
|
+
#
|
12
|
+
# @example the count of all your female friends
|
13
|
+
# Friend.count(:conditions => [ 'gender = ?', 'female' ])
|
14
|
+
#
|
15
|
+
# @example the count of all friends with an address (NULL values are not included)
|
16
|
+
# Friend.count(:address)
|
17
|
+
#
|
18
|
+
# @example the count of all friends with an address that are older then 18
|
19
|
+
# Friend.count(:address, :age.gt => 18)
|
20
|
+
#
|
21
|
+
# @example the count of all your female friends with an address
|
22
|
+
# Friend.count(:address, :conditions => [ 'gender = ?', 'female' ])
|
23
|
+
#
|
24
|
+
# @param property [Symbol] of the property you with to count (optional)
|
25
|
+
# @param opts [Hash, Symbol] the conditions
|
26
|
+
#
|
27
|
+
# @return [Integer] return the count given the conditions
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
def count(*args)
|
31
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
32
|
+
property_name = args.first
|
33
|
+
|
34
|
+
if property_name
|
35
|
+
assert_kind_of 'property', property_by_name(property_name), Property
|
36
|
+
end
|
37
|
+
|
38
|
+
aggregate(query.merge(:fields => [ property_name ? property_name.count : :all.count ]))
|
35
39
|
end
|
36
40
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
aggregate(query.merge(:fields => [ property_name.min ]))
|
61
|
-
end
|
41
|
+
# Get the lowest value of a property
|
42
|
+
#
|
43
|
+
# @example the age of the youngest friend
|
44
|
+
# Friend.min(:age)
|
45
|
+
#
|
46
|
+
# @example the age of the youngest female friend
|
47
|
+
# Friend.min(:age, :conditions => [ 'gender = ?', 'female' ])
|
48
|
+
#
|
49
|
+
# @param property [Symbol] the property you wish to get the lowest value of
|
50
|
+
# @param opts [Hash, Symbol] the conditions
|
51
|
+
#
|
52
|
+
# @return [Integer] return the lowest value of a property given the conditions
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
def min(*args)
|
56
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
57
|
+
property_name = args.first
|
58
|
+
|
59
|
+
assert_property_type property_name, Integer, Float, BigDecimal, DateTime, Date, Time
|
60
|
+
|
61
|
+
aggregate(query.merge(:fields => [ property_name.min ]))
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
64
|
+
# Get the highest value of a property
|
65
|
+
#
|
66
|
+
# @example the age of the oldest friend
|
67
|
+
# Friend.max(:age)
|
68
|
+
#
|
69
|
+
# @example the age of the oldest female friend
|
70
|
+
# Friend.max(:age, :conditions => [ 'gender = ?', 'female' ])
|
71
|
+
#
|
72
|
+
# @param property [Symbol] the property you wish to get the highest value of
|
73
|
+
# @param opts [Hash, Symbol] the conditions
|
74
|
+
#
|
75
|
+
# @return [Integer] return the highest value of a property given the conditions
|
76
|
+
#
|
77
|
+
# @api public
|
78
|
+
def max(*args)
|
79
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
80
|
+
property_name = args.first
|
81
|
+
|
82
|
+
assert_property_type property_name, Integer, Float, BigDecimal, DateTime, Date, Time
|
83
|
+
|
84
|
+
aggregate(query.merge(:fields => [ property_name.max ]))
|
85
|
+
end
|
85
86
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
87
|
+
# Get the average value of a property
|
88
|
+
#
|
89
|
+
# @example the average age of all friends
|
90
|
+
# Friend.avg(:age)
|
91
|
+
#
|
92
|
+
# @example the average age of all female friends
|
93
|
+
# Friend.avg(:age, :conditions => [ 'gender = ?', 'female' ])
|
94
|
+
#
|
95
|
+
# @param property [Symbol] the property you wish to get the average value of
|
96
|
+
# @param opts [Hash, Symbol] the conditions
|
97
|
+
#
|
98
|
+
# @return [Integer] return the average value of a property given the conditions
|
99
|
+
#
|
100
|
+
# @api public
|
101
|
+
def avg(*args)
|
102
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
103
|
+
property_name = args.first
|
104
|
+
|
105
|
+
assert_property_type property_name, Integer, Float, BigDecimal
|
106
|
+
|
107
|
+
aggregate(query.merge(:fields => [ property_name.avg ]))
|
108
|
+
end
|
108
109
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
110
|
+
# Get the total value of a property
|
111
|
+
#
|
112
|
+
# @example the total age of all friends
|
113
|
+
# Friend.sum(:age)
|
114
|
+
#
|
115
|
+
# @example the total age of all female friends
|
116
|
+
# Friend.max(:age, :conditions => [ 'gender = ?', 'female' ])
|
117
|
+
#
|
118
|
+
# @param property [Symbol] the property you wish to get the total value of
|
119
|
+
# @param opts [Hash, Symbol] the conditions
|
120
|
+
#
|
121
|
+
# @return [Integer] return the total value of a property given the conditions
|
122
|
+
#
|
123
|
+
# @api public
|
124
|
+
def sum(*args)
|
125
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
126
|
+
property_name = args.first
|
127
|
+
|
128
|
+
assert_property_type property_name, Integer, Float, BigDecimal
|
129
|
+
|
130
|
+
aggregate(query.merge(:fields => [ property_name.sum ]))
|
131
|
+
end
|
131
132
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
133
|
+
# Perform aggregate queries
|
134
|
+
#
|
135
|
+
# @example the count of friends
|
136
|
+
# Friend.aggregate(:all.count)
|
137
|
+
#
|
138
|
+
# @example the minimum age, the maximum age and the total age of friends
|
139
|
+
# Friend.aggregate(:age.min, :age.max, :age.sum)
|
140
|
+
#
|
141
|
+
# @example the average age, grouped by gender
|
142
|
+
# Friend.aggregate(:age.avg, :fields => [ :gender ])
|
143
|
+
#
|
144
|
+
# @param aggregates [Symbol, ...] operators to aggregate with
|
145
|
+
# @params query [Hash] the conditions
|
146
|
+
#
|
147
|
+
# @return [Array,Numeric,DateTime,Date,Time] the results of the
|
148
|
+
# aggregate query
|
149
|
+
#
|
150
|
+
# @api public
|
151
|
+
def aggregate(*args)
|
152
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
153
|
+
|
154
|
+
query[:fields] ||= []
|
155
|
+
query[:fields] |= args
|
156
|
+
query[:fields].map! { |f| normalize_field(f) }
|
157
|
+
query[:order] ||= query[:fields].select { |p| p.kind_of?(Property) }
|
158
|
+
|
159
|
+
raise ArgumentError, 'query[:fields] must not be empty' if query[:fields].empty?
|
160
|
+
|
161
|
+
query = scoped_query(query)
|
162
|
+
|
163
|
+
if query.fields.any? { |p| p.kind_of?(Property) }
|
164
|
+
query.repository.aggregate(query.update(:unique => true))
|
165
|
+
else
|
166
|
+
query.repository.aggregate(query).first # only return one row
|
167
|
+
end
|
167
168
|
end
|
168
|
-
end
|
169
169
|
|
170
|
-
|
170
|
+
private
|
171
171
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
172
|
+
def assert_property_type(name, *types)
|
173
|
+
if name.nil?
|
174
|
+
raise ArgumentError, 'property name must not be nil'
|
175
|
+
end
|
176
176
|
|
177
|
-
|
177
|
+
type = property_by_name(name).type
|
178
178
|
|
179
|
-
|
180
|
-
|
179
|
+
unless types.include?(type)
|
180
|
+
raise ArgumentError, "#{name} must be #{types * ' or '}, but was #{type}"
|
181
|
+
end
|
181
182
|
end
|
182
|
-
end
|
183
183
|
|
184
|
-
|
185
|
-
|
184
|
+
def normalize_field(field)
|
185
|
+
assert_kind_of 'field', field, DataMapper::Query::Operator, Symbol, Property
|
186
|
+
|
187
|
+
case field
|
188
|
+
when DataMapper::Query::Operator
|
189
|
+
if field.target == :all
|
190
|
+
field
|
191
|
+
else
|
192
|
+
field.class.new(property_by_name(field.target), field.operator)
|
193
|
+
end
|
194
|
+
|
195
|
+
when Symbol
|
196
|
+
property_by_name(field)
|
186
197
|
|
187
|
-
|
188
|
-
when Query::Operator
|
189
|
-
if field.target == :all
|
198
|
+
when Property
|
190
199
|
field
|
191
|
-
|
192
|
-
field.class.new(property_by_name(field.target), field.operator)
|
193
|
-
end
|
194
|
-
when Symbol
|
195
|
-
property_by_name(field)
|
196
|
-
when Property
|
197
|
-
field
|
200
|
+
end
|
198
201
|
end
|
199
202
|
end
|
200
203
|
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
module DataMapper
|
2
|
-
|
3
|
-
|
2
|
+
module Aggregates
|
3
|
+
module Collection
|
4
|
+
include Functions
|
4
5
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# def size
|
7
|
+
# loaded? ? super : count
|
8
|
+
# end
|
8
9
|
|
9
|
-
|
10
|
+
private
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
def property_by_name(property_name)
|
13
|
+
properties[property_name]
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
data/lib/dm-aggregates/model.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
module DataMapper
|
2
|
-
module
|
3
|
-
|
2
|
+
module Aggregates
|
3
|
+
module Model
|
4
|
+
include Functions
|
4
5
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# def size
|
7
|
+
# count
|
8
|
+
# end
|
8
9
|
|
9
|
-
|
10
|
+
private
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
def property_by_name(property_name)
|
13
|
+
properties(repository.name)[property_name]
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Aggregates
|
3
|
+
module Query
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
6
|
+
# FIXME: figure out a cleaner approach than AMC
|
7
|
+
alias assert_valid_fields_without_operator assert_valid_fields
|
8
|
+
alias assert_valid_fields assert_valid_fields_with_operator
|
9
|
+
RUBY
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert_valid_fields_with_operator(fields, unique)
|
13
|
+
operators, fields = fields.partition { |f| f.kind_of?(DataMapper::Query::Operator) }
|
14
|
+
|
15
|
+
operators.each do |operator|
|
16
|
+
target = operator.target
|
17
|
+
|
18
|
+
unless target == :all || target.kind_of?(Property) && target.model == model && @properties.include?(target)
|
19
|
+
raise ArgumentError, "+options[:fields]+ entry #{target.inspect} does not map to a property in #{model}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_valid_fields_without_operator(fields, unique)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/dm-aggregates.rb
CHANGED
@@ -1,15 +1,26 @@
|
|
1
|
-
require '
|
1
|
+
require 'dm-aggregates/adapters/data_objects_adapter'
|
2
|
+
require 'dm-aggregates/aggregate_functions'
|
3
|
+
require 'dm-aggregates/collection'
|
4
|
+
require 'dm-aggregates/core_ext/symbol'
|
5
|
+
require 'dm-aggregates/model'
|
6
|
+
require 'dm-aggregates/query'
|
7
|
+
require 'dm-aggregates/repository'
|
8
|
+
require 'dm-aggregates/version'
|
2
9
|
|
3
|
-
|
10
|
+
module DataMapper
|
11
|
+
class Repository
|
12
|
+
include Aggregates::Repository
|
13
|
+
end
|
4
14
|
|
5
|
-
|
6
|
-
|
7
|
-
|
15
|
+
module Model
|
16
|
+
include Aggregates::Model
|
17
|
+
end
|
8
18
|
|
19
|
+
class Collection
|
20
|
+
include Aggregates::Collection
|
21
|
+
end
|
9
22
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
require dir + 'adapters' + 'data_objects_adapter'
|
15
|
-
require dir + 'support' + 'symbol'
|
23
|
+
class Query
|
24
|
+
include Aggregates::Query
|
25
|
+
end
|
26
|
+
end
|
data/spec/public/model_spec.rb
CHANGED
data/spec/spec.opts
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
-
require 'pathname'
|
2
1
|
require 'rubygems'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
# use local dm-core if running from a typical dev checkout.
|
4
|
+
lib = File.join('..', '..', 'dm-core', 'lib')
|
5
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
6
|
+
require 'dm-core'
|
7
|
+
|
8
|
+
# Support running specs with 'rake spec' and 'spec'
|
9
|
+
$LOAD_PATH.unshift('lib') unless $LOAD_PATH.include?('lib')
|
10
|
+
|
11
|
+
require 'dm-aggregates'
|
12
|
+
|
13
|
+
require 'public/shared/aggregate_shared_spec'
|
7
14
|
|
8
15
|
def load_driver(name, default_uri)
|
9
16
|
return false if ENV['ADAPTER'] != name.to_s
|
data/tasks/install.rb
CHANGED
@@ -4,7 +4,7 @@ end
|
|
4
4
|
|
5
5
|
desc "Install #{GEM_NAME} #{GEM_VERSION}"
|
6
6
|
task :install => [ :package ] do
|
7
|
-
sudo_gem "install
|
7
|
+
sudo_gem "install pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
|
8
8
|
end
|
9
9
|
|
10
10
|
desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
|
data/tasks/spec.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
begin
|
2
|
-
gem 'rspec', '~>1.2'
|
3
|
-
require 'spec'
|
4
2
|
require 'spec/rake/spectask'
|
5
3
|
|
6
4
|
task :default => [ :spec ]
|
@@ -8,16 +6,18 @@ begin
|
|
8
6
|
desc 'Run specifications'
|
9
7
|
Spec::Rake::SpecTask.new(:spec) do |t|
|
10
8
|
t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
|
11
|
-
t.
|
9
|
+
t.libs << 'lib' << 'spec' # needed for CI rake spec task, duplicated in spec_helper
|
12
10
|
|
13
11
|
begin
|
14
|
-
|
12
|
+
require 'rcov'
|
15
13
|
t.rcov = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
|
16
14
|
t.rcov_opts << '--exclude' << 'spec'
|
17
15
|
t.rcov_opts << '--text-summary'
|
18
16
|
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
19
17
|
rescue LoadError
|
20
18
|
# rcov not installed
|
19
|
+
rescue SyntaxError
|
20
|
+
# rcov syntax invalid
|
21
21
|
end
|
22
22
|
end
|
23
23
|
rescue LoadError
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dm-aggregates
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Foy Savas
|
@@ -9,19 +9,10 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: dm-core
|
17
|
-
type: :runtime
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - "="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.9.11
|
24
|
-
version:
|
14
|
+
dependencies: []
|
15
|
+
|
25
16
|
description: DataMapper plugin providing support for aggregates, functions on collections and datasets
|
26
17
|
email:
|
27
18
|
- foysavas [a] gmail [d] com
|
@@ -30,24 +21,25 @@ executables: []
|
|
30
21
|
extensions: []
|
31
22
|
|
32
23
|
extra_rdoc_files:
|
33
|
-
- README.
|
24
|
+
- README.rdoc
|
34
25
|
- LICENSE
|
35
26
|
- TODO
|
36
|
-
- History.
|
27
|
+
- History.rdoc
|
37
28
|
files:
|
38
|
-
- History.
|
29
|
+
- History.rdoc
|
39
30
|
- LICENSE
|
40
31
|
- Manifest.txt
|
41
|
-
- README.
|
32
|
+
- README.rdoc
|
42
33
|
- Rakefile
|
43
34
|
- TODO
|
44
35
|
- lib/dm-aggregates.rb
|
45
36
|
- lib/dm-aggregates/adapters/data_objects_adapter.rb
|
46
37
|
- lib/dm-aggregates/aggregate_functions.rb
|
47
38
|
- lib/dm-aggregates/collection.rb
|
39
|
+
- lib/dm-aggregates/core_ext/symbol.rb
|
48
40
|
- lib/dm-aggregates/model.rb
|
41
|
+
- lib/dm-aggregates/query.rb
|
49
42
|
- lib/dm-aggregates/repository.rb
|
50
|
-
- lib/dm-aggregates/support/symbol.rb
|
51
43
|
- lib/dm-aggregates/version.rb
|
52
44
|
- spec/public/collection_spec.rb
|
53
45
|
- spec/public/model_spec.rb
|
@@ -57,11 +49,13 @@ files:
|
|
57
49
|
- tasks/install.rb
|
58
50
|
- tasks/spec.rb
|
59
51
|
has_rdoc: true
|
60
|
-
homepage: http://github.com/
|
52
|
+
homepage: http://github.com/datamapper/dm-more/tree/master/dm-aggregates
|
53
|
+
licenses: []
|
54
|
+
|
61
55
|
post_install_message:
|
62
56
|
rdoc_options:
|
63
57
|
- --main
|
64
|
-
- README.
|
58
|
+
- README.rdoc
|
65
59
|
require_paths:
|
66
60
|
- lib
|
67
61
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -79,9 +73,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
73
|
requirements: []
|
80
74
|
|
81
75
|
rubyforge_project: datamapper
|
82
|
-
rubygems_version: 1.3.
|
76
|
+
rubygems_version: 1.3.5
|
83
77
|
signing_key:
|
84
|
-
specification_version:
|
78
|
+
specification_version: 3
|
85
79
|
summary: DataMapper plugin providing support for aggregates, functions on collections and datasets
|
86
80
|
test_files: []
|
87
81
|
|
@@ -1,21 +0,0 @@
|
|
1
|
-
class Symbol
|
2
|
-
def count
|
3
|
-
DataMapper::Query::Operator.new(self, :count)
|
4
|
-
end
|
5
|
-
|
6
|
-
def min
|
7
|
-
DataMapper::Query::Operator.new(self, :min)
|
8
|
-
end
|
9
|
-
|
10
|
-
def max
|
11
|
-
DataMapper::Query::Operator.new(self, :max)
|
12
|
-
end
|
13
|
-
|
14
|
-
def avg
|
15
|
-
DataMapper::Query::Operator.new(self, :avg)
|
16
|
-
end
|
17
|
-
|
18
|
-
def sum
|
19
|
-
DataMapper::Query::Operator.new(self, :sum)
|
20
|
-
end
|
21
|
-
end # class Symbol
|