dm-core 0.9.11 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +17 -14
- data/.gitignore +3 -1
- data/FAQ +6 -5
- data/History.txt +5 -50
- data/Manifest.txt +66 -76
- data/QUICKLINKS +1 -1
- data/README.txt +21 -15
- data/Rakefile +6 -7
- data/SPECS +2 -29
- data/TODO +1 -1
- data/deps.rip +2 -0
- data/dm-core.gemspec +11 -15
- data/lib/dm-core.rb +105 -110
- data/lib/dm-core/adapters.rb +135 -16
- data/lib/dm-core/adapters/abstract_adapter.rb +251 -181
- data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
- data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
- data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
- data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
- data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
- data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
- data/lib/dm-core/associations/many_to_many.rb +372 -90
- data/lib/dm-core/associations/many_to_one.rb +220 -73
- data/lib/dm-core/associations/one_to_many.rb +319 -255
- data/lib/dm-core/associations/one_to_one.rb +66 -53
- data/lib/dm-core/associations/relationship.rb +561 -156
- data/lib/dm-core/collection.rb +1101 -379
- data/lib/dm-core/core_ext/kernel.rb +12 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +4 -34
- data/lib/dm-core/migrations.rb +1283 -0
- data/lib/dm-core/model.rb +570 -369
- data/lib/dm-core/model/descendant_set.rb +81 -0
- data/lib/dm-core/model/hook.rb +45 -0
- data/lib/dm-core/model/is.rb +32 -0
- data/lib/dm-core/model/property.rb +247 -0
- data/lib/dm-core/model/relationship.rb +335 -0
- data/lib/dm-core/model/scope.rb +90 -0
- data/lib/dm-core/property.rb +808 -273
- data/lib/dm-core/property_set.rb +141 -98
- data/lib/dm-core/query.rb +1037 -483
- data/lib/dm-core/query/conditions/comparison.rb +872 -0
- data/lib/dm-core/query/conditions/operation.rb +221 -0
- data/lib/dm-core/query/direction.rb +43 -0
- data/lib/dm-core/query/operator.rb +84 -0
- data/lib/dm-core/query/path.rb +138 -0
- data/lib/dm-core/query/sort.rb +45 -0
- data/lib/dm-core/repository.rb +210 -94
- data/lib/dm-core/resource.rb +641 -421
- data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
- data/lib/dm-core/support/chainable.rb +22 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/logger.rb +13 -0
- data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
- data/lib/dm-core/transaction.rb +333 -92
- data/lib/dm-core/type.rb +98 -60
- data/lib/dm-core/types/boolean.rb +1 -1
- data/lib/dm-core/types/discriminator.rb +34 -20
- data/lib/dm-core/types/object.rb +7 -4
- data/lib/dm-core/types/paranoid_boolean.rb +11 -9
- data/lib/dm-core/types/paranoid_datetime.rb +11 -9
- data/lib/dm-core/types/serial.rb +3 -3
- data/lib/dm-core/types/text.rb +3 -4
- data/lib/dm-core/version.rb +1 -1
- data/script/performance.rb +102 -109
- data/script/profile.rb +169 -38
- data/spec/lib/adapter_helpers.rb +105 -0
- data/spec/lib/collection_helpers.rb +18 -0
- data/spec/lib/counter_adapter.rb +34 -0
- data/spec/lib/pending_helpers.rb +27 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
- data/spec/public/associations/many_to_many_spec.rb +193 -0
- data/spec/public/associations/many_to_one_spec.rb +73 -0
- data/spec/public/associations/one_to_many_spec.rb +77 -0
- data/spec/public/associations/one_to_one_spec.rb +156 -0
- data/spec/public/collection_spec.rb +65 -0
- data/spec/public/migrations_spec.rb +359 -0
- data/spec/public/model/relationship_spec.rb +924 -0
- data/spec/public/model_spec.rb +159 -0
- data/spec/public/property_spec.rb +829 -0
- data/spec/public/resource_spec.rb +71 -0
- data/spec/public/sel_spec.rb +44 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +317 -0
- data/spec/public/shared/collection_shared_spec.rb +1670 -0
- data/spec/public/shared/finder_shared_spec.rb +1619 -0
- data/spec/public/shared/resource_shared_spec.rb +924 -0
- data/spec/public/shared/sel_shared_spec.rb +112 -0
- data/spec/public/transaction_spec.rb +129 -0
- data/spec/public/types/discriminator_spec.rb +130 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +194 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +142 -0
- data/spec/semipublic/property_spec.rb +61 -0
- data/spec/semipublic/query/conditions_spec.rb +528 -0
- data/spec/semipublic/query/path_spec.rb +443 -0
- data/spec/semipublic/query_spec.rb +2626 -0
- data/spec/semipublic/resource_spec.rb +47 -0
- data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
- data/spec/spec.opts +3 -1
- data/spec/spec_helper.rb +80 -57
- data/tasks/ci.rb +19 -31
- data/tasks/dm.rb +43 -48
- data/tasks/doc.rb +8 -11
- data/tasks/gemspec.rb +5 -5
- data/tasks/hoe.rb +15 -16
- data/tasks/install.rb +8 -10
- metadata +74 -111
- data/lib/dm-core/associations.rb +0 -207
- data/lib/dm-core/associations/relationship_chain.rb +0 -81
- data/lib/dm-core/auto_migrations.rb +0 -105
- data/lib/dm-core/dependency_queue.rb +0 -32
- data/lib/dm-core/hook.rb +0 -11
- data/lib/dm-core/is.rb +0 -16
- data/lib/dm-core/logger.rb +0 -232
- data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
- data/lib/dm-core/migrator.rb +0 -29
- data/lib/dm-core/scope.rb +0 -58
- data/lib/dm-core/support.rb +0 -7
- data/lib/dm-core/support/array.rb +0 -13
- data/lib/dm-core/support/assertions.rb +0 -8
- data/lib/dm-core/support/errors.rb +0 -23
- data/lib/dm-core/support/kernel.rb +0 -11
- data/lib/dm-core/support/symbol.rb +0 -41
- data/lib/dm-core/type_map.rb +0 -80
- data/lib/dm-core/types.rb +0 -19
- data/script/all +0 -4
- data/spec/integration/association_spec.rb +0 -1382
- data/spec/integration/association_through_spec.rb +0 -203
- data/spec/integration/associations/many_to_many_spec.rb +0 -449
- data/spec/integration/associations/many_to_one_spec.rb +0 -163
- data/spec/integration/associations/one_to_many_spec.rb +0 -188
- data/spec/integration/auto_migrations_spec.rb +0 -413
- data/spec/integration/collection_spec.rb +0 -1073
- data/spec/integration/data_objects_adapter_spec.rb +0 -32
- data/spec/integration/dependency_queue_spec.rb +0 -46
- data/spec/integration/model_spec.rb +0 -197
- data/spec/integration/mysql_adapter_spec.rb +0 -85
- data/spec/integration/postgres_adapter_spec.rb +0 -731
- data/spec/integration/property_spec.rb +0 -253
- data/spec/integration/query_spec.rb +0 -514
- data/spec/integration/repository_spec.rb +0 -61
- data/spec/integration/resource_spec.rb +0 -513
- data/spec/integration/sqlite3_adapter_spec.rb +0 -352
- data/spec/integration/sti_spec.rb +0 -273
- data/spec/integration/strategic_eager_loading_spec.rb +0 -156
- data/spec/integration/transaction_spec.rb +0 -75
- data/spec/integration/type_spec.rb +0 -275
- data/spec/lib/logging_helper.rb +0 -18
- data/spec/lib/mock_adapter.rb +0 -27
- data/spec/lib/model_loader.rb +0 -100
- data/spec/lib/publicize_methods.rb +0 -28
- data/spec/models/content.rb +0 -16
- data/spec/models/vehicles.rb +0 -34
- data/spec/models/zoo.rb +0 -48
- data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
- data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
- data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
- data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
- data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
- data/spec/unit/associations/many_to_many_spec.rb +0 -32
- data/spec/unit/associations/many_to_one_spec.rb +0 -159
- data/spec/unit/associations/one_to_many_spec.rb +0 -393
- data/spec/unit/associations/one_to_one_spec.rb +0 -7
- data/spec/unit/associations/relationship_spec.rb +0 -71
- data/spec/unit/associations_spec.rb +0 -242
- data/spec/unit/auto_migrations_spec.rb +0 -111
- data/spec/unit/collection_spec.rb +0 -182
- data/spec/unit/data_mapper_spec.rb +0 -35
- data/spec/unit/identity_map_spec.rb +0 -126
- data/spec/unit/is_spec.rb +0 -80
- data/spec/unit/migrator_spec.rb +0 -33
- data/spec/unit/model_spec.rb +0 -321
- data/spec/unit/naming_conventions_spec.rb +0 -36
- data/spec/unit/property_set_spec.rb +0 -90
- data/spec/unit/property_spec.rb +0 -753
- data/spec/unit/query_spec.rb +0 -571
- data/spec/unit/repository_spec.rb +0 -93
- data/spec/unit/resource_spec.rb +0 -649
- data/spec/unit/scope_spec.rb +0 -142
- data/spec/unit/transaction_spec.rb +0 -493
- data/spec/unit/type_map_spec.rb +0 -114
- data/spec/unit/type_spec.rb +0 -119
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require "benchmark"
|
|
2
|
+
|
|
3
|
+
module DataMapper::Spec
|
|
4
|
+
module AdapterHelpers
|
|
5
|
+
def self.current_adapters
|
|
6
|
+
@current_adapters ||= []
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def supported_by(*adapters, &block)
|
|
10
|
+
adapters = get_adapters(*adapters)
|
|
11
|
+
|
|
12
|
+
PRIMARY.only(*adapters).each do |adapter, connection_uri|
|
|
13
|
+
# keep track of the current adapters
|
|
14
|
+
AdapterHelpers.current_adapters << adapters
|
|
15
|
+
|
|
16
|
+
describe("with #{adapter}") do
|
|
17
|
+
|
|
18
|
+
before :all do
|
|
19
|
+
# store these in instance vars for the shared adapter specs
|
|
20
|
+
@adapter = DataMapper.setup(:default, connection_uri)
|
|
21
|
+
@repository = DataMapper.repository(@adapter.name)
|
|
22
|
+
|
|
23
|
+
# create all tables and constraints before each spec
|
|
24
|
+
if @repository.respond_to?(:auto_migrate!)
|
|
25
|
+
@repository.auto_migrate!
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
after :all do
|
|
30
|
+
# remove all tables and constraints after each spec
|
|
31
|
+
if DataMapper.respond_to?(:auto_migrate_down!, true)
|
|
32
|
+
DataMapper.send(:auto_migrate_down!, @repository.name)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# TODO: add destroy_model_storage and migrations code
|
|
37
|
+
# that removes the YAML file and remove this code
|
|
38
|
+
after :all do
|
|
39
|
+
if defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
|
|
40
|
+
descendants = DataMapper::Model.descendants.to_a
|
|
41
|
+
while model = descendants.shift
|
|
42
|
+
descendants.concat(model.descendants.to_a - [ model ])
|
|
43
|
+
|
|
44
|
+
model.default_scope.clear
|
|
45
|
+
model.all(:repository => @repository).destroy!
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
self.instance_eval(&block)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
AdapterHelpers.current_adapters.pop
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def with_alternate_adapter(&block)
|
|
58
|
+
adapters = AdapterHelpers.current_adapters.last
|
|
59
|
+
|
|
60
|
+
ALTERNATE.only(*adapters).each do |adapter, connection_uri|
|
|
61
|
+
describe("and #{adapter}") do
|
|
62
|
+
|
|
63
|
+
before :all do
|
|
64
|
+
@alternate_adapter = DataMapper.setup(:alternate, connection_uri)
|
|
65
|
+
@alternate_repository = DataMapper.repository(@alternate_adapter.name)
|
|
66
|
+
|
|
67
|
+
# create all tables and constraints before each spec
|
|
68
|
+
if @alternate_repository.respond_to?(:auto_migrate!)
|
|
69
|
+
@alternate_repository.auto_migrate!
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
after :all do
|
|
74
|
+
# remove all tables and constraints after each spec
|
|
75
|
+
if DataMapper.respond_to?(:auto_migrate_down!, true)
|
|
76
|
+
DataMapper.send(:auto_migrate_down!, @alternate_repository.name)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# TODO: add destroy_model_storage and migrations code
|
|
81
|
+
# that removes the YAML file and remove this code
|
|
82
|
+
after :all do
|
|
83
|
+
if defined?(DataMapper::Adapters::YamlAdapter) && @alternate_adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
|
|
84
|
+
descendants = DataMapper::Model.descendants.to_a
|
|
85
|
+
while model = descendants.shift
|
|
86
|
+
descendants.concat(model.descendants.to_a - [ model ])
|
|
87
|
+
|
|
88
|
+
model.default_scope.clear
|
|
89
|
+
model.all(:repository => @alternate_repository).destroy!
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
self.instance_eval(&block)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def get_adapters(*adapters)
|
|
100
|
+
adapters.map! { |adapter_name| adapter_name.to_s }
|
|
101
|
+
adapters = ADAPTERS if adapters.include?('all')
|
|
102
|
+
ADAPTERS & adapters
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module DataMapper::Spec
|
|
2
|
+
module CollectionHelpers
|
|
3
|
+
module GroupMethods
|
|
4
|
+
def self.extended(base)
|
|
5
|
+
base.class_inheritable_accessor :loaded
|
|
6
|
+
base.loaded = false
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def should_not_be_a_kicker
|
|
10
|
+
unless loaded
|
|
11
|
+
it 'should not be a kicker' do
|
|
12
|
+
@articles.should_not be_loaded
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class CounterAdapter < DataMapper::Adapters::AbstractAdapter
|
|
2
|
+
instance_methods.each { |method| undef_method method unless %w[ __id__ __send__ send class dup object_id kind_of? instance_of? respond_to? equal? assert_kind_of should should_not instance_variable_set instance_variable_get extend ].include?(method.to_s) }
|
|
3
|
+
|
|
4
|
+
attr_reader :counts
|
|
5
|
+
|
|
6
|
+
def kind_of?(klass)
|
|
7
|
+
super || @adapter.kind_of?(klass)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def instance_of?(klass)
|
|
11
|
+
super || @adapter.instance_of?(klass)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def respond_to?(method, include_private = false)
|
|
15
|
+
super || @adapter.respond_to?(method, include_private)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def initialize(adapter)
|
|
21
|
+
@counts = Hash.new { |hash, key| hash[key] = 0 }
|
|
22
|
+
@adapter = adapter
|
|
23
|
+
@count = 0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def increment_count_for(method)
|
|
27
|
+
@counts[method] += 1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def method_missing(method, *args, &block)
|
|
31
|
+
increment_count_for(method)
|
|
32
|
+
@adapter.send(method, *args, &block)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module DataMapper::Spec
|
|
2
|
+
module PendingHelpers
|
|
3
|
+
def pending_if(message, boolean = true)
|
|
4
|
+
if boolean
|
|
5
|
+
pending(message) { yield }
|
|
6
|
+
else
|
|
7
|
+
yield
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def rescue_if(message, boolean = true)
|
|
12
|
+
if boolean
|
|
13
|
+
raised = nil
|
|
14
|
+
begin
|
|
15
|
+
yield
|
|
16
|
+
raised = false
|
|
17
|
+
rescue Exception
|
|
18
|
+
raised = true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
raise 'should have raised' if raised == false
|
|
22
|
+
else
|
|
23
|
+
yield
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'spec/runner/formatter/base_text_formatter'
|
|
2
|
+
|
|
3
|
+
# Code is based on standard SpecdocFormatter, but will print full error details as soon as they are found.
|
|
4
|
+
# Successful or pending examples are written only as a dot in the output. Header is only printed if errors occur.
|
|
5
|
+
#
|
|
6
|
+
# To use it, add the following to your spec/spec.opts:
|
|
7
|
+
# --require
|
|
8
|
+
# lib/rspec_immediate_feedback_formatter.rb
|
|
9
|
+
# --format
|
|
10
|
+
# Spec::Runner::Formatter::ImmediateFeedbackFormatter
|
|
11
|
+
|
|
12
|
+
module Spec
|
|
13
|
+
module Runner
|
|
14
|
+
module Formatter
|
|
15
|
+
class ImmediateFeedbackFormatter < BaseTextFormatter
|
|
16
|
+
|
|
17
|
+
def add_example_group(example_group)
|
|
18
|
+
super
|
|
19
|
+
@current_group = example_group.description
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def example_failed(example, counter, failure)
|
|
23
|
+
if @current_group
|
|
24
|
+
output.puts
|
|
25
|
+
output.puts @current_group
|
|
26
|
+
@current_group = nil # only print the group name once
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
message = if failure.expectation_not_met?
|
|
30
|
+
"- #{example.description} (FAILED - #{counter})"
|
|
31
|
+
else
|
|
32
|
+
"- #{example.description} (ERROR - #{counter})"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
output.puts(red(message))
|
|
36
|
+
dump_failure(counter, failure) # dump stacktrace immediately
|
|
37
|
+
output.flush
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def example_passed(*)
|
|
41
|
+
output.print green('.')
|
|
42
|
+
output.flush
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def example_pending(*)
|
|
46
|
+
super
|
|
47
|
+
output.print yellow('*')
|
|
48
|
+
output.flush
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
share_examples_for 'A Limited Many to Many Collection' do
|
|
4
|
+
describe '#destroy!' do
|
|
5
|
+
describe 'on a limited collection' do
|
|
6
|
+
before :all do
|
|
7
|
+
@other = @articles.create
|
|
8
|
+
@limited = @articles.all(:limit => 1)
|
|
9
|
+
|
|
10
|
+
@return = @limited.destroy!
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should only remove the join resource for the destroyed resource' do
|
|
14
|
+
@join_model.all.should_not be_empty
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# run the specs once with a loaded association and once not
|
|
21
|
+
[ false, true ].each do |loaded|
|
|
22
|
+
describe 'Many to Many Associations with :through => Resource' do
|
|
23
|
+
extend DataMapper::Spec::CollectionHelpers::GroupMethods
|
|
24
|
+
|
|
25
|
+
self.loaded = loaded
|
|
26
|
+
|
|
27
|
+
# define the model prior to supported_by
|
|
28
|
+
before :all do
|
|
29
|
+
module ::Blog
|
|
30
|
+
class Author
|
|
31
|
+
include DataMapper::Resource
|
|
32
|
+
|
|
33
|
+
property :id, Serial
|
|
34
|
+
property :name, String
|
|
35
|
+
|
|
36
|
+
has n, :articles, :through => Resource
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Article
|
|
40
|
+
include DataMapper::Resource
|
|
41
|
+
|
|
42
|
+
property :id, Serial
|
|
43
|
+
property :title, String, :nullable => false
|
|
44
|
+
property :content, Text
|
|
45
|
+
property :subtitle, String
|
|
46
|
+
|
|
47
|
+
has n, :authors, :through => Resource
|
|
48
|
+
belongs_to :original, self, :nullable => true
|
|
49
|
+
has n, :revisions, self, :child_key => [ :original_id ]
|
|
50
|
+
has 1, :previous, self, :child_key => [ :original_id ], :order => [ :id.desc ]
|
|
51
|
+
has n, :publications, :through => Resource
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class Publication
|
|
55
|
+
include DataMapper::Resource
|
|
56
|
+
|
|
57
|
+
property :id, Serial
|
|
58
|
+
property :name, String
|
|
59
|
+
|
|
60
|
+
has n, :articles, :through => Resource
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
@author_model = Blog::Author
|
|
65
|
+
@article_model = Blog::Article
|
|
66
|
+
@publication_model = Blog::Publication
|
|
67
|
+
|
|
68
|
+
# initialize the join model
|
|
69
|
+
Blog::Author.relationships(:default)[:articles].through
|
|
70
|
+
|
|
71
|
+
@join_model = Blog::ArticleAuthor
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
supported_by :all do
|
|
75
|
+
before :all do
|
|
76
|
+
@author = @author_model.create(:name => 'Dan Kubb')
|
|
77
|
+
|
|
78
|
+
@original = @author.articles.create(:title => 'Original Article')
|
|
79
|
+
@article = @author.articles.create(:title => 'Sample Article', :content => 'Sample', :original => @original)
|
|
80
|
+
@other = @author.articles.create(:title => 'Other Article', :content => 'Other')
|
|
81
|
+
|
|
82
|
+
# load the targets without references to a single source
|
|
83
|
+
load_collection = lambda do |query|
|
|
84
|
+
@author_model.get(*@author.key).articles(query)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
@articles = load_collection.call(:title => 'Sample Article')
|
|
88
|
+
@other_articles = load_collection.call(:title => 'Other Article')
|
|
89
|
+
|
|
90
|
+
@articles.entries if loaded
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it_should_behave_like 'A public Collection'
|
|
94
|
+
it_should_behave_like 'A public Association Collection'
|
|
95
|
+
it_should_behave_like 'A Collection supporting Strategic Eager Loading' unless loaded
|
|
96
|
+
it_should_behave_like 'Finder Interface'
|
|
97
|
+
it_should_behave_like 'A Limited Many to Many Collection'
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe 'Many to Many Associations :through => one_to_many' do
|
|
102
|
+
extend DataMapper::Spec::CollectionHelpers::GroupMethods
|
|
103
|
+
|
|
104
|
+
self.loaded = loaded
|
|
105
|
+
|
|
106
|
+
# define the model prior to supported_by
|
|
107
|
+
before :all do
|
|
108
|
+
module ::Blog
|
|
109
|
+
class Author
|
|
110
|
+
include DataMapper::Resource
|
|
111
|
+
|
|
112
|
+
property :id, Serial
|
|
113
|
+
property :name, String
|
|
114
|
+
|
|
115
|
+
has n, :sites
|
|
116
|
+
has n, :articles, :through => :sites
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class Site
|
|
120
|
+
include DataMapper::Resource
|
|
121
|
+
|
|
122
|
+
property :name, String, :key => true, :default => 'default'
|
|
123
|
+
|
|
124
|
+
belongs_to :author
|
|
125
|
+
has n, :articles
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
class Article
|
|
129
|
+
include DataMapper::Resource
|
|
130
|
+
|
|
131
|
+
property :id, Serial
|
|
132
|
+
property :title, String, :nullable => false
|
|
133
|
+
property :content, Text
|
|
134
|
+
property :subtitle, String
|
|
135
|
+
|
|
136
|
+
property :site_name, String, :default => 'default'
|
|
137
|
+
|
|
138
|
+
belongs_to :site
|
|
139
|
+
has n, :authors, :through => :site
|
|
140
|
+
belongs_to :original, self, :nullable => true
|
|
141
|
+
has n, :revisions, self, :child_key => [ :original_id ]
|
|
142
|
+
has 1, :previous, self, :child_key => [ :original_id ], :order => [ :id.desc ]
|
|
143
|
+
has n, :publications, :through => Resource
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class Publication
|
|
147
|
+
include DataMapper::Resource
|
|
148
|
+
|
|
149
|
+
property :id, Serial
|
|
150
|
+
property :name, String
|
|
151
|
+
|
|
152
|
+
has n, :articles, :through => Resource
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
@author_model = Blog::Author
|
|
157
|
+
@article_model = Blog::Article
|
|
158
|
+
@publication_model = Blog::Publication
|
|
159
|
+
|
|
160
|
+
@join_model = Blog::Site
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
supported_by :all do
|
|
164
|
+
before :all do
|
|
165
|
+
@author = @author_model.create(:name => 'Dan Kubb')
|
|
166
|
+
|
|
167
|
+
@original_site = @author.sites.create(:name => 'original')
|
|
168
|
+
@article_site = @author.sites.create(:name => 'article')
|
|
169
|
+
@other_site = @author.sites.create(:name => 'other')
|
|
170
|
+
|
|
171
|
+
@original = @original_site.articles.create(:title => 'Original Article')
|
|
172
|
+
@article = @article_site.articles.create(:title => 'Sample Article', :content => 'Sample', :original => @original)
|
|
173
|
+
@other = @other_site.articles.create(:title => 'Other Article', :content => 'Other')
|
|
174
|
+
|
|
175
|
+
# load the targets without references to a single source
|
|
176
|
+
load_collection = lambda do |query|
|
|
177
|
+
@author_model.get(*@author.key).articles(query)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
@articles = load_collection.call(:title => 'Sample Article')
|
|
181
|
+
@other_articles = load_collection.call(:title => 'Other Article')
|
|
182
|
+
|
|
183
|
+
@articles.entries if loaded
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it_should_behave_like 'A public Collection'
|
|
187
|
+
it_should_behave_like 'A public Association Collection'
|
|
188
|
+
it_should_behave_like 'A Collection supporting Strategic Eager Loading' unless loaded
|
|
189
|
+
it_should_behave_like 'Finder Interface'
|
|
190
|
+
it_should_behave_like 'A Limited Many to Many Collection'
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
describe 'Many to One Associations' do
|
|
4
|
+
before :all do
|
|
5
|
+
module ::Blog
|
|
6
|
+
class User
|
|
7
|
+
include DataMapper::Resource
|
|
8
|
+
|
|
9
|
+
property :name, String, :key => true
|
|
10
|
+
property :age, Integer
|
|
11
|
+
property :summary, Text
|
|
12
|
+
property :description, Text
|
|
13
|
+
property :admin, Boolean, :accessor => :private
|
|
14
|
+
|
|
15
|
+
belongs_to :referrer, self, :nullable => true
|
|
16
|
+
has n, :comments
|
|
17
|
+
|
|
18
|
+
# FIXME: figure out a different approach than stubbing things out
|
|
19
|
+
def comment=(*)
|
|
20
|
+
# do nothing with comment
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class Author < User; end
|
|
25
|
+
|
|
26
|
+
class Comment
|
|
27
|
+
include DataMapper::Resource
|
|
28
|
+
|
|
29
|
+
property :id, Serial
|
|
30
|
+
property :body, Text
|
|
31
|
+
|
|
32
|
+
belongs_to :user
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class Article
|
|
36
|
+
include DataMapper::Resource
|
|
37
|
+
|
|
38
|
+
property :id, Serial
|
|
39
|
+
property :body, Text
|
|
40
|
+
|
|
41
|
+
has n, :paragraphs
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Paragraph
|
|
45
|
+
include DataMapper::Resource
|
|
46
|
+
|
|
47
|
+
property :id, Serial
|
|
48
|
+
property :text, String
|
|
49
|
+
|
|
50
|
+
belongs_to :article
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
@user_model = Blog::User
|
|
55
|
+
@author_model = Blog::Author
|
|
56
|
+
@comment_model = Blog::Comment
|
|
57
|
+
@article_model = Blog::Article
|
|
58
|
+
@paragraph_model = Blog::Paragraph
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
supported_by :all do
|
|
62
|
+
before :all do
|
|
63
|
+
user = @user_model.create(:name => 'dbussink', :age => 25, :description => 'Test')
|
|
64
|
+
comment = @comment_model.create(:body => 'Cool spec', :user => user)
|
|
65
|
+
|
|
66
|
+
@comment = @comment_model.get(*comment.key)
|
|
67
|
+
@user = @comment.user
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it_should_behave_like 'A public Resource'
|
|
71
|
+
it_should_behave_like 'A Resource supporting Strategic Eager Loading'
|
|
72
|
+
end
|
|
73
|
+
end
|