mack-data_mapper 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/gems/addressable-2.0.0/lib/addressable/idna.rb +4867 -0
- data/lib/gems/addressable-2.0.0/lib/addressable/uri.rb +2469 -0
- data/lib/gems/addressable-2.0.0/lib/addressable/version.rb +35 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/adapters/data_objects_adapter.rb +85 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/aggregate_functions.rb +201 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/collection.rb +11 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/model.rb +11 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/repository.rb +7 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/support/symbol.rb +21 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/version.rb +7 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates.rb +15 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/abstract_adapter.rb +209 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/data_objects_adapter.rb +709 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/in_memory_adapter.rb +87 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/mysql_adapter.rb +136 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/postgres_adapter.rb +188 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters.rb +22 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/many_to_many.rb +147 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/many_to_one.rb +107 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/one_to_many.rb +318 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/one_to_one.rb +61 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/relationship.rb +223 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/relationship_chain.rb +81 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations.rb +200 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/auto_migrations.rb +105 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/collection.rb +642 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/dependency_queue.rb +32 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/hook.rb +11 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/identity_map.rb +42 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/is.rb +16 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/logger.rb +232 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/migrations/destructive_migrations.rb +17 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/migrator.rb +29 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/model.rb +488 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/naming_conventions.rb +84 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/property.rb +663 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/property_set.rb +169 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/query.rb +628 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/repository.rb +159 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/resource.rb +637 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/scope.rb +58 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/array.rb +13 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/assertions.rb +8 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/errors.rb +23 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/kernel.rb +11 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/symbol.rb +41 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support.rb +7 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/transaction.rb +267 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/type.rb +160 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/type_map.rb +80 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/boolean.rb +7 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/discriminator.rb +34 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/object.rb +24 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/paranoid_boolean.rb +34 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/paranoid_datetime.rb +33 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/serial.rb +9 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/text.rb +10 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types.rb +19 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/version.rb +3 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core.rb +217 -0
- data/lib/gems/dm-core-0.9.7/script/all +5 -0
- data/lib/gems/dm-core-0.9.7/script/performance.rb +284 -0
- data/lib/gems/dm-core-0.9.7/script/profile.rb +87 -0
- data/lib/gems/dm-migrations-0.9.7/lib/dm-migrations/version.rb +5 -0
- data/lib/gems/dm-migrations-0.9.7/lib/dm-migrations.rb +1 -0
- data/lib/gems/dm-migrations-0.9.7/lib/migration.rb +215 -0
- data/lib/gems/dm-migrations-0.9.7/lib/migration_runner.rb +88 -0
- data/lib/gems/dm-migrations-0.9.7/lib/spec/example/migration_example_group.rb +73 -0
- data/lib/gems/dm-migrations-0.9.7/lib/spec/matchers/migration_matchers.rb +107 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/column.rb +9 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/mysql.rb +52 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/postgresql.rb +78 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/sqlite3.rb +43 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/table.rb +19 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/table_creator.rb +81 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/table_modifier.rb +53 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql.rb +10 -0
- data/lib/gems/dm-observer-0.9.7/lib/dm-observer/version.rb +5 -0
- data/lib/gems/dm-observer-0.9.7/lib/dm-observer.rb +91 -0
- data/lib/gems/dm-serializer-0.9.7/lib/dm-serializer/version.rb +5 -0
- data/lib/gems/dm-serializer-0.9.7/lib/dm-serializer.rb +183 -0
- data/lib/gems/dm-timestamps-0.9.7/lib/dm-timestamps/version.rb +5 -0
- data/lib/gems/dm-timestamps-0.9.7/lib/dm-timestamps.rb +57 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/bcrypt_hash.rb +31 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/csv.rb +28 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/enum.rb +70 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/epoch_time.rb +27 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/file_path.rb +27 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/flag.rb +61 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/ip_address.rb +30 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/json.rb +40 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/regexp.rb +20 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/serial.rb +8 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/slug.rb +37 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/uri.rb +29 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/uuid.rb +64 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/version.rb +5 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/yaml.rb +36 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types.rb +28 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/absent_field_validator.rb +60 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/acceptance_validator.rb +76 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/auto_validate.rb +153 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/block_validator.rb +60 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/confirmation_validator.rb +80 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/contextual_validators.rb +56 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/custom_validator.rb +72 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/format_validator.rb +97 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/formats/email.rb +40 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/formats/url.rb +20 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/generic_validator.rb +100 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/length_validator.rb +113 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/method_validator.rb +68 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/numeric_validator.rb +83 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/primitive_validator.rb +60 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/required_field_validator.rb +88 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/support/object.rb +5 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/uniqueness_validator.rb +64 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/validation_errors.rb +63 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/version.rb +5 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/within_validator.rb +53 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations.rb +234 -0
- data/lib/gems/json_pure-1.1.3/GPL +340 -0
- data/lib/gems/json_pure-1.1.3/VERSION +1 -0
- data/lib/gems/json_pure-1.1.3/bin/edit_json.rb +10 -0
- data/lib/gems/json_pure-1.1.3/bin/prettify_json.rb +76 -0
- data/lib/gems/json_pure-1.1.3/lib/json/Array.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/FalseClass.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/Hash.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/Key.xpm +73 -0
- data/lib/gems/json_pure-1.1.3/lib/json/NilClass.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/Numeric.xpm +28 -0
- data/lib/gems/json_pure-1.1.3/lib/json/String.xpm +96 -0
- data/lib/gems/json_pure-1.1.3/lib/json/TrueClass.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/add/core.rb +135 -0
- data/lib/gems/json_pure-1.1.3/lib/json/add/rails.rb +58 -0
- data/lib/gems/json_pure-1.1.3/lib/json/common.rb +354 -0
- data/lib/gems/json_pure-1.1.3/lib/json/editor.rb +1362 -0
- data/lib/gems/json_pure-1.1.3/lib/json/ext.rb +13 -0
- data/lib/gems/json_pure-1.1.3/lib/json/json.xpm +1499 -0
- data/lib/gems/json_pure-1.1.3/lib/json/pure/generator.rb +394 -0
- data/lib/gems/json_pure-1.1.3/lib/json/pure/parser.rb +259 -0
- data/lib/gems/json_pure-1.1.3/lib/json/pure.rb +75 -0
- data/lib/gems/json_pure-1.1.3/lib/json/version.rb +9 -0
- data/lib/gems/json_pure-1.1.3/lib/json.rb +235 -0
- data/lib/gems/launchy-0.3.2/bin/launchy +12 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/application.rb +163 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/browser.rb +85 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/command_line.rb +48 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/gemspec.rb +53 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/specification.rb +133 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/version.rb +18 -0
- data/lib/gems/launchy-0.3.2/lib/launchy.rb +58 -0
- data/lib/gems/uuidtools-1.0.3/lib/uuidtools/version.rb +32 -0
- data/lib/gems/uuidtools-1.0.3/lib/uuidtools.rb +648 -0
- data/lib/gems.rb +13 -0
- data/lib/mack-data_mapper/migration_generator/migration_generator.rb +5 -0
- data/lib/mack-data_mapper/migration_generator/templates/db/migrations/%=@migration_name%.rb.template +1 -1
- data/lib/mack-data_mapper/model_generator/manifest.yml +3 -3
- data/lib/mack-data_mapper/model_generator/model_generator.rb +8 -1
- data/lib/mack-data_mapper/model_generator/templates/model.rb.template +1 -1
- data/lib/mack-data_mapper/model_generator/templates/rspec.rb.template +1 -1
- data/lib/mack-data_mapper/model_generator/templates/test_case.rb.template +1 -1
- data/lib/mack-data_mapper.rb +3 -2
- data/lib/mack-data_mapper_tasks.rb +7 -0
- metadata +235 -86
@@ -0,0 +1,35 @@
|
|
1
|
+
#--
|
2
|
+
# Addressable, Copyright (c) 2006-2008 Bob Aman
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
# Used to prevent the class/module from being loaded more than once
|
25
|
+
if !defined?(Addressable::VERSION)
|
26
|
+
module Addressable
|
27
|
+
module VERSION #:nodoc:
|
28
|
+
MAJOR = 2
|
29
|
+
MINOR = 0
|
30
|
+
TINY = 0
|
31
|
+
|
32
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Adapters
|
3
|
+
class DataObjectsAdapter
|
4
|
+
def aggregate(query)
|
5
|
+
with_reader(read_statement(query), query.bind_values) do |reader|
|
6
|
+
results = []
|
7
|
+
|
8
|
+
while(reader.next!) do
|
9
|
+
row = query.fields.zip(reader.values).map do |field,value|
|
10
|
+
if field.respond_to?(:operator)
|
11
|
+
send(field.operator, field.target, value)
|
12
|
+
else
|
13
|
+
field.typecast(value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
results << (query.fields.size > 1 ? row : row[0])
|
18
|
+
end
|
19
|
+
|
20
|
+
results
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def count(property, value)
|
27
|
+
value.to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
def min(property, value)
|
31
|
+
property.typecast(value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def max(property, value)
|
35
|
+
property.typecast(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def avg(property, value)
|
39
|
+
property.type == Integer ? value.to_f : property.typecast(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
def sum(property, value)
|
43
|
+
property.typecast(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
module SQL
|
47
|
+
private
|
48
|
+
|
49
|
+
alias original_property_to_column_name property_to_column_name
|
50
|
+
|
51
|
+
def property_to_column_name(repository, property, qualify)
|
52
|
+
case property
|
53
|
+
when Query::Operator
|
54
|
+
aggregate_field_statement(repository, property.operator, property.target, qualify)
|
55
|
+
when Property, Query::Path
|
56
|
+
original_property_to_column_name(repository, property, qualify)
|
57
|
+
else
|
58
|
+
raise ArgumentError, "+property+ must be a DataMapper::Query::Operator, a DataMapper::Property or a Query::Path, but was a #{property.class} (#{property.inspect})"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def aggregate_field_statement(repository, aggregate_function, property, qualify)
|
63
|
+
column_name = if aggregate_function == :count && property == :all
|
64
|
+
'*'
|
65
|
+
else
|
66
|
+
property_to_column_name(repository, property, qualify)
|
67
|
+
end
|
68
|
+
|
69
|
+
function_name = case aggregate_function
|
70
|
+
when :count then 'COUNT'
|
71
|
+
when :min then 'MIN'
|
72
|
+
when :max then 'MAX'
|
73
|
+
when :avg then 'AVG'
|
74
|
+
when :sum then 'SUM'
|
75
|
+
else raise "Invalid aggregate function: #{aggregate_function.inspect}"
|
76
|
+
end
|
77
|
+
|
78
|
+
"#{function_name}(#{column_name})"
|
79
|
+
end
|
80
|
+
end # module SQL
|
81
|
+
|
82
|
+
include SQL
|
83
|
+
end # class DataObjectsAdapter
|
84
|
+
end # module Adapters
|
85
|
+
end # module DataMapper
|
@@ -0,0 +1,201 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module AggregateFunctions
|
3
|
+
# Count results (given the conditions)
|
4
|
+
#
|
5
|
+
# @example the count of all friends
|
6
|
+
# Friend.count
|
7
|
+
#
|
8
|
+
# @example the count of all friends older then 18
|
9
|
+
# Friend.count(:age.gt => 18)
|
10
|
+
#
|
11
|
+
# @example the count of all your female friends
|
12
|
+
# Friend.count(:conditions => [ 'gender = ?', 'female' ])
|
13
|
+
#
|
14
|
+
# @example the count of all friends with an address (NULL values are not included)
|
15
|
+
# Friend.count(:address)
|
16
|
+
#
|
17
|
+
# @example the count of all friends with an address that are older then 18
|
18
|
+
# Friend.count(:address, :age.gt => 18)
|
19
|
+
#
|
20
|
+
# @example the count of all your female friends with an address
|
21
|
+
# Friend.count(:address, :conditions => [ 'gender = ?', 'female' ])
|
22
|
+
#
|
23
|
+
# @param property [Symbol] of the property you with to count (optional)
|
24
|
+
# @param opts [Hash, Symbol] the conditions
|
25
|
+
#
|
26
|
+
# @return [Integer] return the count given the conditions
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
def count(*args)
|
30
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
31
|
+
property_name = args.first
|
32
|
+
|
33
|
+
if property_name
|
34
|
+
assert_kind_of 'property', property_by_name(property_name), Property
|
35
|
+
end
|
36
|
+
|
37
|
+
aggregate(query.merge(:fields => [ property_name ? property_name.count : :all.count ]))
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get the lowest value of a property
|
41
|
+
#
|
42
|
+
# @example the age of the youngest friend
|
43
|
+
# Friend.min(:age)
|
44
|
+
#
|
45
|
+
# @example the age of the youngest female friend
|
46
|
+
# Friend.min(:age, :conditions => [ 'gender = ?', 'female' ])
|
47
|
+
#
|
48
|
+
# @param property [Symbol] the property you wish to get the lowest value of
|
49
|
+
# @param opts [Hash, Symbol] the conditions
|
50
|
+
#
|
51
|
+
# @return [Integer] return the lowest value of a property given the conditions
|
52
|
+
#
|
53
|
+
# @api public
|
54
|
+
def min(*args)
|
55
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
56
|
+
property_name = args.first
|
57
|
+
|
58
|
+
assert_property_type property_name, Integer, Float, BigDecimal, DateTime, Date, Time
|
59
|
+
|
60
|
+
aggregate(query.merge(:fields => [ property_name.min ]))
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get the highest value of a property
|
64
|
+
#
|
65
|
+
# @example the age of the oldest friend
|
66
|
+
# Friend.max(:age)
|
67
|
+
#
|
68
|
+
# @example the age of the oldest female friend
|
69
|
+
# Friend.max(:age, :conditions => [ 'gender = ?', 'female' ])
|
70
|
+
#
|
71
|
+
# @param property [Symbol] the property you wish to get the highest value of
|
72
|
+
# @param opts [Hash, Symbol] the conditions
|
73
|
+
#
|
74
|
+
# @return [Integer] return the highest value of a property given the conditions
|
75
|
+
#
|
76
|
+
# @api public
|
77
|
+
def max(*args)
|
78
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
79
|
+
property_name = args.first
|
80
|
+
|
81
|
+
assert_property_type property_name, Integer, Float, BigDecimal, DateTime, Date, Time
|
82
|
+
|
83
|
+
aggregate(query.merge(:fields => [ property_name.max ]))
|
84
|
+
end
|
85
|
+
|
86
|
+
# Get the average value of a property
|
87
|
+
#
|
88
|
+
# @example the average age of all friends
|
89
|
+
# Friend.avg(:age)
|
90
|
+
#
|
91
|
+
# @example the average age of all female friends
|
92
|
+
# Friend.avg(:age, :conditions => [ 'gender = ?', 'female' ])
|
93
|
+
#
|
94
|
+
# @param property [Symbol] the property you wish to get the average value of
|
95
|
+
# @param opts [Hash, Symbol] the conditions
|
96
|
+
#
|
97
|
+
# @return [Integer] return the average value of a property given the conditions
|
98
|
+
#
|
99
|
+
# @api public
|
100
|
+
def avg(*args)
|
101
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
102
|
+
property_name = args.first
|
103
|
+
|
104
|
+
assert_property_type property_name, Integer, Float, BigDecimal
|
105
|
+
|
106
|
+
aggregate(query.merge(:fields => [ property_name.avg ]))
|
107
|
+
end
|
108
|
+
|
109
|
+
# Get the total value of a property
|
110
|
+
#
|
111
|
+
# @example the total age of all friends
|
112
|
+
# Friend.sum(:age)
|
113
|
+
#
|
114
|
+
# @example the total age of all female friends
|
115
|
+
# Friend.max(:age, :conditions => [ 'gender = ?', 'female' ])
|
116
|
+
#
|
117
|
+
# @param property [Symbol] the property you wish to get the total value of
|
118
|
+
# @param opts [Hash, Symbol] the conditions
|
119
|
+
#
|
120
|
+
# @return [Integer] return the total value of a property given the conditions
|
121
|
+
#
|
122
|
+
# @api public
|
123
|
+
def sum(*args)
|
124
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
125
|
+
property_name = args.first
|
126
|
+
|
127
|
+
assert_property_type property_name, Integer, Float, BigDecimal
|
128
|
+
|
129
|
+
aggregate(query.merge(:fields => [ property_name.sum ]))
|
130
|
+
end
|
131
|
+
|
132
|
+
# Perform aggregate queries
|
133
|
+
#
|
134
|
+
# @example the count of friends
|
135
|
+
# Friend.aggregate(:all.count)
|
136
|
+
#
|
137
|
+
# @example the minimum age, the maximum age and the total age of friends
|
138
|
+
# Friend.aggregate(:age.min, :age.max, :age.sum)
|
139
|
+
#
|
140
|
+
# @example the average age, grouped by gender
|
141
|
+
# Friend.aggregate(:age.avg, :fields => [ :gender ])
|
142
|
+
#
|
143
|
+
# @param aggregates [Symbol, ...] operators to aggregate with
|
144
|
+
# @params query [Hash] the conditions
|
145
|
+
#
|
146
|
+
# @return [Array,Numeric,DateTime,Date,Time] the results of the
|
147
|
+
# aggregate query
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
def aggregate(*args)
|
151
|
+
query = args.last.kind_of?(Hash) ? args.pop : {}
|
152
|
+
|
153
|
+
query[:fields] ||= []
|
154
|
+
query[:fields] |= args
|
155
|
+
query[:fields].map! { |f| normalize_field(f) }
|
156
|
+
query[:order] ||= query[:fields].select { |p| p.kind_of?(Property) }
|
157
|
+
|
158
|
+
raise ArgumentError, 'query[:fields] must not be empty' if query[:fields].empty?
|
159
|
+
|
160
|
+
query = scoped_query(query)
|
161
|
+
|
162
|
+
if query.fields.any? { |p| p.kind_of?(Property) }
|
163
|
+
# explicitly specify the fields to circumvent a bug in Query#update
|
164
|
+
query.repository.aggregate(query.update(:fields => query.fields, :unique => true))
|
165
|
+
else
|
166
|
+
query.repository.aggregate(query).first # only return one row
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def assert_property_type(name, *types)
|
173
|
+
if name.nil?
|
174
|
+
raise ArgumentError, 'property name must not be nil'
|
175
|
+
end
|
176
|
+
|
177
|
+
type = property_by_name(name).type
|
178
|
+
|
179
|
+
unless types.include?(type)
|
180
|
+
raise ArgumentError, "#{name} must be #{types * ' or '}, but was #{type}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def normalize_field(field)
|
185
|
+
assert_kind_of 'field', field, Query::Operator, Symbol, Property
|
186
|
+
|
187
|
+
case field
|
188
|
+
when 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
|
+
when Symbol
|
195
|
+
property_by_name(field)
|
196
|
+
when Property
|
197
|
+
field
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
dir = Pathname(__FILE__).dirname.expand_path + 'dm-aggregates'
|
4
|
+
|
5
|
+
require dir + 'version'
|
6
|
+
gem 'dm-core', DataMapper::More::Aggregates::VERSION
|
7
|
+
require 'dm-core'
|
8
|
+
|
9
|
+
|
10
|
+
require dir + 'aggregate_functions'
|
11
|
+
require dir + 'model'
|
12
|
+
require dir + 'repository'
|
13
|
+
require dir + 'collection'
|
14
|
+
require dir + 'adapters' + 'data_objects_adapter'
|
15
|
+
require dir + 'support' + 'symbol'
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Adapters
|
3
|
+
class AbstractAdapter
|
4
|
+
include Assertions
|
5
|
+
|
6
|
+
attr_reader :name, :uri
|
7
|
+
attr_accessor :resource_naming_convention, :field_naming_convention
|
8
|
+
|
9
|
+
def create(resources)
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
def read_many(query)
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_one(query)
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def update(attributes, query)
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete(query)
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def normalize_uri(uri_or_options)
|
32
|
+
uri_or_options
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Instantiate an Adapter by passing it a DataMapper::Repository
|
38
|
+
# connection string for configuration.
|
39
|
+
def initialize(name, uri_or_options)
|
40
|
+
assert_kind_of 'name', name, Symbol
|
41
|
+
assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, DataObjects::URI, Hash, String
|
42
|
+
|
43
|
+
@name = name
|
44
|
+
@uri = normalize_uri(uri_or_options)
|
45
|
+
|
46
|
+
@resource_naming_convention = NamingConventions::Resource::UnderscoredAndPluralized
|
47
|
+
@field_naming_convention = NamingConventions::Field::Underscored
|
48
|
+
|
49
|
+
@transactions = {}
|
50
|
+
end
|
51
|
+
|
52
|
+
# TODO: move to dm-more/dm-migrations
|
53
|
+
module Migration
|
54
|
+
#
|
55
|
+
# Returns whether the storage_name exists.
|
56
|
+
#
|
57
|
+
# @param storage_name<String> a String defining the name of a storage,
|
58
|
+
# for example a table name.
|
59
|
+
#
|
60
|
+
# @return <Boolean> true if the storage exists
|
61
|
+
#
|
62
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
63
|
+
def storage_exists?(storage_name)
|
64
|
+
raise NotImplementedError
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Returns whether the field exists.
|
69
|
+
#
|
70
|
+
# @param storage_name<String> a String defining the name of a storage, for example a table name.
|
71
|
+
# @param field_name<String> a String defining the name of a field, for example a column name.
|
72
|
+
#
|
73
|
+
# @return <Boolean> true if the field exists.
|
74
|
+
#
|
75
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
76
|
+
def field_exists?(storage_name, field_name)
|
77
|
+
raise NotImplementedError
|
78
|
+
end
|
79
|
+
|
80
|
+
# TODO: move to dm-more/dm-migrations
|
81
|
+
def upgrade_model_storage(repository, model)
|
82
|
+
raise NotImplementedError
|
83
|
+
end
|
84
|
+
|
85
|
+
# TODO: move to dm-more/dm-migrations
|
86
|
+
def create_model_storage(repository, model)
|
87
|
+
raise NotImplementedError
|
88
|
+
end
|
89
|
+
|
90
|
+
# TODO: move to dm-more/dm-migrations
|
91
|
+
def destroy_model_storage(repository, model)
|
92
|
+
raise NotImplementedError
|
93
|
+
end
|
94
|
+
|
95
|
+
# TODO: move to dm-more/dm-migrations
|
96
|
+
def alter_model_storage(repository, *args)
|
97
|
+
raise NotImplementedError
|
98
|
+
end
|
99
|
+
|
100
|
+
# TODO: move to dm-more/dm-migrations
|
101
|
+
def create_property_storage(repository, property)
|
102
|
+
raise NotImplementedError
|
103
|
+
end
|
104
|
+
|
105
|
+
# TODO: move to dm-more/dm-migrations
|
106
|
+
def destroy_property_storage(repository, property)
|
107
|
+
raise NotImplementedError
|
108
|
+
end
|
109
|
+
|
110
|
+
# TODO: move to dm-more/dm-migrations
|
111
|
+
def alter_property_storage(repository, *args)
|
112
|
+
raise NotImplementedError
|
113
|
+
end
|
114
|
+
|
115
|
+
module ClassMethods
|
116
|
+
# Default TypeMap for all adapters.
|
117
|
+
#
|
118
|
+
# @return <DataMapper::TypeMap> default TypeMap
|
119
|
+
#
|
120
|
+
# TODO: move to dm-more/dm-migrations
|
121
|
+
def type_map
|
122
|
+
@type_map ||= TypeMap.new
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
include Migration
|
128
|
+
extend Migration::ClassMethods
|
129
|
+
|
130
|
+
# TODO: move to dm-more/dm-transaction
|
131
|
+
module Transaction
|
132
|
+
#
|
133
|
+
# Pushes the given Transaction onto the per thread Transaction stack so
|
134
|
+
# that everything done by this Adapter is done within the context of said
|
135
|
+
# Transaction.
|
136
|
+
#
|
137
|
+
# @param transaction<DataMapper::Transaction> a Transaction to be the
|
138
|
+
# 'current' transaction until popped.
|
139
|
+
#
|
140
|
+
# TODO: move to dm-more/dm-transaction
|
141
|
+
def push_transaction(transaction)
|
142
|
+
transactions(Thread.current) << transaction
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# Pop the 'current' Transaction from the per thread Transaction stack so
|
147
|
+
# that everything done by this Adapter is no longer necessarily within the
|
148
|
+
# context of said Transaction.
|
149
|
+
#
|
150
|
+
# @return <DataMapper::Transaction> the former 'current' transaction.
|
151
|
+
#
|
152
|
+
# TODO: move to dm-more/dm-transaction
|
153
|
+
def pop_transaction
|
154
|
+
transactions(Thread.current).pop
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# Retrieve the current transaction for this Adapter.
|
159
|
+
#
|
160
|
+
# Everything done by this Adapter is done within the context of this
|
161
|
+
# Transaction.
|
162
|
+
#
|
163
|
+
# @return <DataMapper::Transaction> the 'current' transaction for this Adapter.
|
164
|
+
#
|
165
|
+
# TODO: move to dm-more/dm-transaction
|
166
|
+
def current_transaction
|
167
|
+
transactions(Thread.current).last
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Returns whether we are within a Transaction.
|
172
|
+
#
|
173
|
+
# @return <Boolean> whether we are within a Transaction.
|
174
|
+
#
|
175
|
+
# TODO: move to dm-more/dm-transaction
|
176
|
+
def within_transaction?
|
177
|
+
!current_transaction.nil?
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# Produces a fresh transaction primitive for this Adapter
|
182
|
+
#
|
183
|
+
# Used by DataMapper::Transaction to perform its various tasks.
|
184
|
+
#
|
185
|
+
# @return <Object> a new Object that responds to :close, :begin, :commit,
|
186
|
+
# :rollback, :rollback_prepared and :prepare
|
187
|
+
#
|
188
|
+
# TODO: move to dm-more/dm-transaction (if possible)
|
189
|
+
def transaction_primitive
|
190
|
+
raise NotImplementedError
|
191
|
+
end
|
192
|
+
|
193
|
+
private
|
194
|
+
def transactions(thread)
|
195
|
+
unless @transactions[thread]
|
196
|
+
@transactions.delete_if do |key, value|
|
197
|
+
!key.respond_to?(:alive?) || !key.alive?
|
198
|
+
end
|
199
|
+
@transactions[thread] = []
|
200
|
+
end
|
201
|
+
@transactions[thread]
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
include Transaction
|
207
|
+
end # class AbstractAdapter
|
208
|
+
end # module Adapters
|
209
|
+
end # module DataMapper
|