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
data/spec/lib/logging_helper.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
module LoggingHelper
|
|
2
|
-
def logger
|
|
3
|
-
class << DataMapper.logger
|
|
4
|
-
attr_writer :log
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
old_log = DataMapper.logger.log
|
|
8
|
-
|
|
9
|
-
begin
|
|
10
|
-
StringIO.new('') do |io|
|
|
11
|
-
DataMapper.logger.log = io
|
|
12
|
-
yield io
|
|
13
|
-
end
|
|
14
|
-
ensure
|
|
15
|
-
DataMapper.logger.log = old_log
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
data/spec/lib/mock_adapter.rb
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
module DataMapper
|
|
2
|
-
module Adapters
|
|
3
|
-
class MockAdapter < DataMapper::Adapters::DataObjectsAdapter
|
|
4
|
-
|
|
5
|
-
def create(resources)
|
|
6
|
-
1
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def exists?(storage_name)
|
|
10
|
-
true
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
module DataObjects
|
|
18
|
-
module Mock
|
|
19
|
-
|
|
20
|
-
def self.logger
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def self.logger=(value)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
end
|
|
27
|
-
end
|
data/spec/lib/model_loader.rb
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# ---
|
|
2
|
-
# Overview
|
|
3
|
-
# ========
|
|
4
|
-
# ModelLoader is a method for loading methods models for specs in a way
|
|
5
|
-
# that will ensure that each spec will be an a pristine state when run.
|
|
6
|
-
#
|
|
7
|
-
# The problem is that if a spec needs to modify a model, the modifications
|
|
8
|
-
# should not carry over to the next spec. As such, all models are
|
|
9
|
-
# destroyed at the end of the spec and reloaded at the start.
|
|
10
|
-
#
|
|
11
|
-
# The second problem is that DataMapper::Resource keeps track
|
|
12
|
-
# of every class that it is included in. This is used for automigration.
|
|
13
|
-
# A number of specs run automigrate, and we don't want all the classes
|
|
14
|
-
# that were defined in other specs to be migrated as well.
|
|
15
|
-
#
|
|
16
|
-
# Usage
|
|
17
|
-
# =====
|
|
18
|
-
#
|
|
19
|
-
# Sets the specified model metaphors to be loaded before each spec and
|
|
20
|
-
# destroyed after each spec in the current example group. This method
|
|
21
|
-
# can be used in a describe block or in a before block.
|
|
22
|
-
#
|
|
23
|
-
# ==== Parameters
|
|
24
|
-
# *metaphor<Symbol>:: The name of the metaphor to load (this is just the filename of
|
|
25
|
-
# file in specs/models)
|
|
26
|
-
#
|
|
27
|
-
# ==== Example
|
|
28
|
-
#
|
|
29
|
-
# describe "DataMapper::Associations" do
|
|
30
|
-
#
|
|
31
|
-
# load_models_for_metaphor :zoo, :blog
|
|
32
|
-
#
|
|
33
|
-
# it "should be awesome" do
|
|
34
|
-
# Zoo.new.should be_awesome
|
|
35
|
-
# end
|
|
36
|
-
# end
|
|
37
|
-
module ModelLoader
|
|
38
|
-
|
|
39
|
-
def self.included(base)
|
|
40
|
-
base.extend(ClassMethods)
|
|
41
|
-
base.class_eval { include InstanceMethods }
|
|
42
|
-
# base.before(:each) { load_models(:global) }
|
|
43
|
-
base.after(:each) { unload_models }
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
module ClassMethods
|
|
47
|
-
|
|
48
|
-
def load_models_for_metaphor(*metaphors)
|
|
49
|
-
before(:each) { load_models_for_metaphor(*metaphors) }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
module InstanceMethods
|
|
55
|
-
|
|
56
|
-
def load_models_for_metaphor(*metaphors)
|
|
57
|
-
files = metaphors.map { |m| DataMapper.root / "spec" / "models" / "#{m}.rb" }
|
|
58
|
-
|
|
59
|
-
klasses = object_space_classes.dup
|
|
60
|
-
files.each { |file| load file }
|
|
61
|
-
loaded_models.concat(object_space_classes - klasses)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def unload_models
|
|
65
|
-
while model = loaded_models.pop
|
|
66
|
-
remove_model(model)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def loaded_models
|
|
71
|
-
@loaded_models ||= []
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
private
|
|
75
|
-
|
|
76
|
-
def object_space_classes
|
|
77
|
-
klasses = []
|
|
78
|
-
ObjectSpace.each_object(Class) {|o| klasses << o}
|
|
79
|
-
klasses
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def remove_model(klass)
|
|
83
|
-
DataMapper::Resource.descendants.delete(klass)
|
|
84
|
-
# Check to see if the model is living inside a module
|
|
85
|
-
klass_name = klass.to_s
|
|
86
|
-
if klass_name.index("::")
|
|
87
|
-
mod = klass_name.match(/(\S+)::/)[1]
|
|
88
|
-
child_class = klass_name.match(/\S+::(\S+)/)[1]
|
|
89
|
-
|
|
90
|
-
Object.const_get(mod).module_eval { remove_const child_class }
|
|
91
|
-
else
|
|
92
|
-
Object.module_eval { remove_const klass.to_s }
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
Spec::Runner.configure do |config|
|
|
99
|
-
config.include(ModelLoader)
|
|
100
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
class Class
|
|
2
|
-
def publicize_methods
|
|
3
|
-
klass = class << self; self; end
|
|
4
|
-
|
|
5
|
-
saved_private_class_methods = klass.private_instance_methods
|
|
6
|
-
saved_protected_class_methods = klass.protected_instance_methods
|
|
7
|
-
saved_private_instance_methods = self.private_instance_methods
|
|
8
|
-
saved_protected_instance_methods = self.protected_instance_methods
|
|
9
|
-
|
|
10
|
-
self.class_eval do
|
|
11
|
-
klass.send(:public, *saved_private_class_methods)
|
|
12
|
-
klass.send(:public, *saved_protected_class_methods)
|
|
13
|
-
public(*saved_private_instance_methods)
|
|
14
|
-
public(*saved_protected_instance_methods)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
begin
|
|
18
|
-
yield
|
|
19
|
-
ensure
|
|
20
|
-
self.class_eval do
|
|
21
|
-
klass.send(:private, *saved_private_class_methods)
|
|
22
|
-
klass.send(:protected, *saved_protected_class_methods)
|
|
23
|
-
private(*saved_private_instance_methods)
|
|
24
|
-
protected(*saved_protected_instance_methods)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
data/spec/models/content.rb
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module Content
|
|
2
|
-
class Dialect
|
|
3
|
-
include DataMapper::Resource
|
|
4
|
-
|
|
5
|
-
property :id, Serial
|
|
6
|
-
property :name, String
|
|
7
|
-
property :code, String
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
class Locale
|
|
11
|
-
include DataMapper::Resource
|
|
12
|
-
|
|
13
|
-
property :id, Serial
|
|
14
|
-
property :name, String
|
|
15
|
-
end
|
|
16
|
-
end
|
data/spec/models/vehicles.rb
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# ==========================
|
|
2
|
-
# Used for Association specs
|
|
3
|
-
# ---
|
|
4
|
-
# These models will probably
|
|
5
|
-
# end up removed. So, I wouldn't
|
|
6
|
-
# use this metaphor
|
|
7
|
-
class Vehicle
|
|
8
|
-
include DataMapper::Resource
|
|
9
|
-
|
|
10
|
-
property :id, Serial
|
|
11
|
-
property :name, String
|
|
12
|
-
|
|
13
|
-
class << self
|
|
14
|
-
attr_accessor :mock_relationship
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class Manufacturer
|
|
19
|
-
include DataMapper::Resource
|
|
20
|
-
|
|
21
|
-
property :id, Serial
|
|
22
|
-
property :name, String
|
|
23
|
-
|
|
24
|
-
class << self
|
|
25
|
-
attr_accessor :mock_relationship
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
class Supplier
|
|
30
|
-
include DataMapper::Resource
|
|
31
|
-
|
|
32
|
-
property :id, Serial
|
|
33
|
-
property :name, String
|
|
34
|
-
end
|
data/spec/models/zoo.rb
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
class Zoo
|
|
2
|
-
include DataMapper::Resource
|
|
3
|
-
|
|
4
|
-
property :id, Serial
|
|
5
|
-
property :name, String
|
|
6
|
-
property :description, Text
|
|
7
|
-
property :inception, DateTime
|
|
8
|
-
property :open, Boolean, :default => false
|
|
9
|
-
property :size, Integer
|
|
10
|
-
property :mission, Text, :writer => :protected
|
|
11
|
-
|
|
12
|
-
has n, :animals
|
|
13
|
-
|
|
14
|
-
def to_s
|
|
15
|
-
name
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class Species
|
|
20
|
-
include DataMapper::Resource
|
|
21
|
-
|
|
22
|
-
property :id, Serial
|
|
23
|
-
property :name, String
|
|
24
|
-
property :classification, String, :reader => :private
|
|
25
|
-
|
|
26
|
-
has n, :animals
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
class Animal
|
|
30
|
-
include DataMapper::Resource
|
|
31
|
-
|
|
32
|
-
property :id, Serial
|
|
33
|
-
property :name, String
|
|
34
|
-
|
|
35
|
-
belongs_to :zoo
|
|
36
|
-
belongs_to :species
|
|
37
|
-
belongs_to :keeper
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
class Employee
|
|
41
|
-
include DataMapper::Resource
|
|
42
|
-
|
|
43
|
-
property :name, String, :key => true
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
class Keeper < Employee
|
|
47
|
-
has n, :animals
|
|
48
|
-
end
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
require 'monitor'
|
|
2
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
|
3
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'adapters', 'adapter_shared_spec'))
|
|
4
|
-
|
|
5
|
-
describe DataMapper::Adapters::AbstractAdapter do
|
|
6
|
-
|
|
7
|
-
before do
|
|
8
|
-
@adapter = DataMapper::Adapters::AbstractAdapter.new(:default, 'mock_uri_string')
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it_should_behave_like 'a DataMapper Adapter'
|
|
12
|
-
|
|
13
|
-
describe "when handling transactions" do
|
|
14
|
-
before :each do
|
|
15
|
-
@transaction = DataMapper::Transaction.new(@adapter)
|
|
16
|
-
end
|
|
17
|
-
it "should be able to push and pop transactions on the current stack" do
|
|
18
|
-
@adapter.current_transaction.should == nil
|
|
19
|
-
@adapter.within_transaction?.should == false
|
|
20
|
-
@adapter.push_transaction(@transaction)
|
|
21
|
-
@adapter.current_transaction.should == @transaction
|
|
22
|
-
@adapter.within_transaction?.should == true
|
|
23
|
-
@adapter.push_transaction(@transaction)
|
|
24
|
-
@adapter.current_transaction.should == @transaction
|
|
25
|
-
@adapter.within_transaction?.should == true
|
|
26
|
-
@adapter.pop_transaction
|
|
27
|
-
@adapter.current_transaction.should == @transaction
|
|
28
|
-
@adapter.within_transaction?.should == true
|
|
29
|
-
@adapter.pop_transaction
|
|
30
|
-
@adapter.current_transaction.should == nil
|
|
31
|
-
@adapter.within_transaction?.should == false
|
|
32
|
-
end
|
|
33
|
-
it "should let each Thread have its own transaction stack" do
|
|
34
|
-
lock = Monitor.new
|
|
35
|
-
transaction2 = DataMapper::Transaction.new(@adapter)
|
|
36
|
-
@adapter.within_transaction?.should == false
|
|
37
|
-
@adapter.current_transaction.should == nil
|
|
38
|
-
@adapter.push_transaction(transaction2)
|
|
39
|
-
@adapter.within_transaction?.should == true
|
|
40
|
-
@adapter.current_transaction.should == transaction2
|
|
41
|
-
lock.synchronize do
|
|
42
|
-
Thread.new do
|
|
43
|
-
@adapter.within_transaction?.should == false
|
|
44
|
-
@adapter.current_transaction.should == nil
|
|
45
|
-
@adapter.push_transaction(@transaction)
|
|
46
|
-
@adapter.within_transaction?.should == true
|
|
47
|
-
@adapter.current_transaction.should == @transaction
|
|
48
|
-
lock.synchronize do
|
|
49
|
-
@adapter.within_transaction?.should == true
|
|
50
|
-
@adapter.current_transaction.should == @transaction
|
|
51
|
-
@adapter.pop_transaction
|
|
52
|
-
@adapter.within_transaction?.should == false
|
|
53
|
-
@adapter.current_transaction.should == nil
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
@adapter.within_transaction?.should == true
|
|
57
|
-
@adapter.current_transaction.should == transaction2
|
|
58
|
-
@adapter.pop_transaction
|
|
59
|
-
@adapter.within_transaction?.should == false
|
|
60
|
-
@adapter.current_transaction.should == nil
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it "should raise NotImplementedError when #create is called" do
|
|
66
|
-
lambda { @adapter.create([ :resource ]) }.should raise_error(NotImplementedError)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it "should raise NotImplementedError when #read_many is called" do
|
|
70
|
-
lambda { @adapter.read_many(:query) }.should raise_error(NotImplementedError)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "should raise NotImplementedError when #read_one is called" do
|
|
74
|
-
lambda { @adapter.read_one(:query) }.should raise_error(NotImplementedError)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it "should raise NotImplementedError when #update is called" do
|
|
78
|
-
lambda { @adapter.update(:attributes, :query) }.should raise_error(NotImplementedError)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it "should raise NotImplementedError when #delete is called" do
|
|
82
|
-
lambda { @adapter.delete(:query) }.should raise_error(NotImplementedError)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it "should raise NotImplementedError when #upgrade_model_storage is called" do
|
|
86
|
-
lambda { @adapter.upgrade_model_storage(:repository, :resource) }.should raise_error(NotImplementedError)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it "should raise NotImplementedError when #storage_exists? is called" do
|
|
90
|
-
lambda { @adapter.storage_exists?("hehu") }.should raise_error(NotImplementedError)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it "should raise NotImplementedError when #create_model_storage is called" do
|
|
94
|
-
lambda { @adapter.create_model_storage(:repository, :resource) }.should raise_error(NotImplementedError)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
it "should raise NotImplementedError when #destroy_model_storage is called" do
|
|
98
|
-
lambda { @adapter.destroy_model_storage(:repository, :resource) }.should raise_error(NotImplementedError)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
it "should raise NotImplementedError when #alter_model_storage is called" do
|
|
102
|
-
lambda { @adapter.alter_model_storage(:repository, :resource) }.should raise_error(NotImplementedError)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it "should raise NotImplementedError when #create_property_storage is called" do
|
|
106
|
-
lambda { @adapter.create_property_storage(:repository, :property) }
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it "should raise NotImplementedError when #destroy_property_storage is called" do
|
|
110
|
-
lambda { @adapter.destroy_property_storage(:repository, :property) }
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it "should raise NotImplementedError when #alter_property_storage is called" do
|
|
114
|
-
lambda { @adapter.alter_property_storage(:repository, :property) }
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it "should raise NotImplementedError when #transaction_primitive is called" do
|
|
118
|
-
lambda { @adapter.transaction_primitive }.should raise_error(NotImplementedError)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
it "should clean out dead threads from @transactions" do
|
|
122
|
-
@adapter.instance_eval do @transactions end.size.should == 0
|
|
123
|
-
t = Thread.new do
|
|
124
|
-
@adapter.push_transaction("plur")
|
|
125
|
-
end
|
|
126
|
-
while t.alive?
|
|
127
|
-
sleep 0.1
|
|
128
|
-
end
|
|
129
|
-
@adapter.instance_eval do @transactions end.size.should == 1
|
|
130
|
-
@adapter.push_transaction("ploj")
|
|
131
|
-
@adapter.instance_eval do @transactions end.size.should == 1
|
|
132
|
-
end
|
|
133
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
describe "a DataMapper Adapter", :shared => true do
|
|
3
|
-
|
|
4
|
-
it "should initialize the connection uri" do
|
|
5
|
-
new_adapter = @adapter.class.new(:default, Addressable::URI.parse('some://uri/string'))
|
|
6
|
-
new_adapter.instance_variable_get('@uri').to_s.should == Addressable::URI.parse('some://uri/string').to_s
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
%w{create read_many read_one update delete create_model_storage alter_model_storage destroy_model_storage create_property_storage alter_property_storage destroy_property_storage} .each do |meth|
|
|
10
|
-
it "should have a #{meth} method" do
|
|
11
|
-
@adapter.should respond_to(meth.intern)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
end
|
|
@@ -1,632 +0,0 @@
|
|
|
1
|
-
require 'monitor'
|
|
2
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
|
3
|
-
|
|
4
|
-
require DataMapper.root / 'spec' / 'unit' / 'adapters' / 'adapter_shared_spec'
|
|
5
|
-
|
|
6
|
-
# TODO: make a shared adapter spec for all the DAO objects to adhere to
|
|
7
|
-
|
|
8
|
-
describe DataMapper::Adapters::DataObjectsAdapter do
|
|
9
|
-
before :all do
|
|
10
|
-
class ::Cheese
|
|
11
|
-
include DataMapper::Resource
|
|
12
|
-
property :id, Serial
|
|
13
|
-
property :name, String, :nullable => false
|
|
14
|
-
property :color, String, :default => 'yellow'
|
|
15
|
-
property :notes, String, :length => 100, :lazy => true
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
before do
|
|
20
|
-
@uri = Addressable::URI.parse('mock://localhost')
|
|
21
|
-
@adapter = DataMapper::Adapters::DataObjectsAdapter.new(:default, @uri)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it_should_behave_like 'a DataMapper Adapter'
|
|
25
|
-
|
|
26
|
-
describe "#find_by_sql" do
|
|
27
|
-
|
|
28
|
-
before do
|
|
29
|
-
class ::Plupp
|
|
30
|
-
include DataMapper::Resource
|
|
31
|
-
property :id, Integer, :key => true
|
|
32
|
-
property :name, String
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it "should be added to DataMapper::Model" do
|
|
37
|
-
DataMapper::Model.instance_methods.map { |m| m.to_s }.include?("find_by_sql").should == true
|
|
38
|
-
Plupp.should respond_to(:find_by_sql)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
describe "when called" do
|
|
42
|
-
|
|
43
|
-
before do
|
|
44
|
-
@reader = mock("reader")
|
|
45
|
-
@reader.stub!(:next!).and_return(false)
|
|
46
|
-
@reader.stub!(:close)
|
|
47
|
-
@connection = mock("connection")
|
|
48
|
-
@connection.stub!(:close)
|
|
49
|
-
@command = mock("command")
|
|
50
|
-
@adapter = Plupp.repository.adapter
|
|
51
|
-
@repository = Plupp.repository
|
|
52
|
-
@repository.stub!(:adapter).and_return(@adapter)
|
|
53
|
-
@adapter.stub!(:create_connection).and_return(@connection)
|
|
54
|
-
@adapter.should_receive(:is_a?).any_number_of_times.with(DataMapper::Adapters::DataObjectsAdapter).and_return(true)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
it "should accept a single String argument with or without options hash" do
|
|
58
|
-
@connection.should_receive(:create_command).twice.with("SELECT * FROM plupps").and_return(@command)
|
|
59
|
-
@command.should_receive(:execute_reader).twice.and_return(@reader)
|
|
60
|
-
Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
|
|
61
|
-
Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
|
|
62
|
-
Plupp.find_by_sql("SELECT * FROM plupps").to_a
|
|
63
|
-
Plupp.find_by_sql("SELECT * FROM plupps", :repository => :plupp_repo).to_a
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it "should accept an Array argument with or without options hash" do
|
|
67
|
-
@connection.should_receive(:create_command).twice.with("SELECT * FROM plupps WHERE plur = ?").and_return(@command)
|
|
68
|
-
@command.should_receive(:execute_reader).twice.with("my pretty plur").and_return(@reader)
|
|
69
|
-
Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
|
|
70
|
-
Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
|
|
71
|
-
Plupp.find_by_sql(["SELECT * FROM plupps WHERE plur = ?", "my pretty plur"]).to_a
|
|
72
|
-
Plupp.find_by_sql(["SELECT * FROM plupps WHERE plur = ?", "my pretty plur"], :repository => :plupp_repo).to_a
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "should accept a Query argument with or without options hash" do
|
|
76
|
-
if ADAPTER == :mysql
|
|
77
|
-
@connection.should_receive(:create_command).twice.with('SELECT `name` FROM `plupps` WHERE (`name` = ?) ORDER BY `id`').and_return(@command)
|
|
78
|
-
else
|
|
79
|
-
@connection.should_receive(:create_command).twice.with('SELECT "name" FROM "plupps" WHERE ("name" = ?) ORDER BY "id"').and_return(@command)
|
|
80
|
-
end
|
|
81
|
-
@command.should_receive(:execute_reader).twice.with('my pretty plur').and_return(@reader)
|
|
82
|
-
Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
|
|
83
|
-
Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
|
|
84
|
-
Plupp.find_by_sql(DataMapper::Query.new(@repository, Plupp, "name" => "my pretty plur", :fields => ["name"])).to_a
|
|
85
|
-
Plupp.find_by_sql(DataMapper::Query.new(@repository, Plupp, "name" => "my pretty plur", :fields => ["name"]), :repository => :plupp_repo).to_a
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
it "requires a Repository that is a DataObjectsRepository to work" do
|
|
89
|
-
non_do_adapter = mock("non do adapter")
|
|
90
|
-
non_do_repo = mock("non do repo")
|
|
91
|
-
non_do_repo.stub!(:adapter).and_return(non_do_adapter)
|
|
92
|
-
Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(non_do_repo)
|
|
93
|
-
Proc.new do
|
|
94
|
-
Plupp.find_by_sql(:repository => :plupp_repo)
|
|
95
|
-
end.should raise_error(Exception, /DataObjectsAdapter/)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
it "requires some kind of query to work at all" do
|
|
99
|
-
Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
|
|
100
|
-
Proc.new do
|
|
101
|
-
Plupp.find_by_sql(:repository => :plupp_repo)
|
|
102
|
-
end.should raise_error(Exception, /requires a query/)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
describe '#uri options' do
|
|
110
|
-
it 'should transform a fully specified option hash into a URI' do
|
|
111
|
-
options = {
|
|
112
|
-
:adapter => 'mysql',
|
|
113
|
-
:host => 'davidleal.com',
|
|
114
|
-
:username => 'me',
|
|
115
|
-
:password => 'mypass',
|
|
116
|
-
:port => 5000,
|
|
117
|
-
:database => 'you_can_call_me_al',
|
|
118
|
-
:socket => 'nosock'
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
adapter = DataMapper::Adapters::DataObjectsAdapter.new(:spec, options)
|
|
122
|
-
adapter.uri.should ==
|
|
123
|
-
DataObjects::URI.parse("mysql://me:mypass@davidleal.com:5000/you_can_call_me_al?socket=nosock")
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
it 'should transform a minimal options hash into a URI' do
|
|
127
|
-
options = {
|
|
128
|
-
:adapter => 'mysql',
|
|
129
|
-
:database => 'you_can_call_me_al'
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
adapter = DataMapper::Adapters::DataObjectsAdapter.new(:spec, options)
|
|
133
|
-
adapter.uri.should == DataObjects::URI.parse("mysql:you_can_call_me_al")
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
it 'should accept the uri when no overrides exist' do
|
|
137
|
-
uri = Addressable::URI.parse("protocol:///")
|
|
138
|
-
DataMapper::Adapters::DataObjectsAdapter.new(:spec, uri).uri.should == DataObjects::URI.parse(uri)
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
describe '#create' do
|
|
143
|
-
before do
|
|
144
|
-
@result = mock('result', :to_i => 1, :insert_id => 1)
|
|
145
|
-
|
|
146
|
-
@adapter.stub!(:execute).and_return(@result)
|
|
147
|
-
@adapter.stub!(:supports_returning?).and_return(false)
|
|
148
|
-
|
|
149
|
-
@property = mock('property', :kind_of? => true, :serial? => true, :name => :property, :field => 'property', :custom? => false, :typecast => 'bind value')
|
|
150
|
-
@properties = [ @property ]
|
|
151
|
-
@bind_values = [ 'bind value' ]
|
|
152
|
-
@attributes = mock('attributes', :keys => @properties, :values => @bind_values)
|
|
153
|
-
@model = mock('model', :kind_of? => true, :key => [ @property ], :storage_name => 'models')
|
|
154
|
-
@resource = mock('resource', :model => @model, :dirty_attributes => @attributes)
|
|
155
|
-
|
|
156
|
-
@property.stub!(:set!).and_return(@resource)
|
|
157
|
-
|
|
158
|
-
@statement = 'INSERT INTO "models" ("property") VALUES (?)'
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def do_create
|
|
162
|
-
@adapter.create([ @resource ])
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
it 'should use only dirty properties' do
|
|
166
|
-
@resource.should_receive(:dirty_attributes).with(no_args).and_return(@attributes)
|
|
167
|
-
do_create.should == 1
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
it 'should use the bind values' do
|
|
171
|
-
@attributes.should_receive(:values).with(no_args).and_return(@bind_values)
|
|
172
|
-
|
|
173
|
-
@adapter.should_receive(:execute).with(@statement, *@bind_values).and_return(@result)
|
|
174
|
-
|
|
175
|
-
do_create.should == 1
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
it 'should generate an SQL statement when supports_returning? is true' do
|
|
179
|
-
@property.should_receive(:serial?).with(no_args).and_return(true)
|
|
180
|
-
@adapter.should_receive(:supports_returning?).with(no_args).and_return(true)
|
|
181
|
-
|
|
182
|
-
@statement = 'INSERT INTO "models" ("property") VALUES (?) RETURNING "property"'
|
|
183
|
-
@adapter.should_receive(:execute).with(@statement, 'bind value').and_return(@result)
|
|
184
|
-
|
|
185
|
-
do_create.should == 1
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
it 'should generate an SQL statement when supports_default_values? is true' do
|
|
189
|
-
@bind_values.clear
|
|
190
|
-
@properties.clear
|
|
191
|
-
@adapter.should_receive(:supports_default_values?).with(no_args).and_return(true)
|
|
192
|
-
|
|
193
|
-
@statement = 'INSERT INTO "models" DEFAULT VALUES'
|
|
194
|
-
@adapter.should_receive(:execute).with(@statement).and_return(@result)
|
|
195
|
-
|
|
196
|
-
do_create.should == 1
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
it 'should generate an SQL statement when supports_default_values? is false' do
|
|
200
|
-
@bind_values.clear
|
|
201
|
-
@properties.clear
|
|
202
|
-
@adapter.should_receive(:supports_default_values?).with(no_args).and_return(false)
|
|
203
|
-
|
|
204
|
-
@statement = 'INSERT INTO "models" () VALUES ()'
|
|
205
|
-
@adapter.should_receive(:execute).with(@statement).and_return(@result)
|
|
206
|
-
|
|
207
|
-
do_create.should == 1
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
it 'should return 0 if no rows created' do
|
|
211
|
-
@result.should_receive(:to_i).with(no_args).and_return(0)
|
|
212
|
-
do_create.should == 0
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
it 'should return 1 if number of rows created is 1' do
|
|
216
|
-
@result.should_receive(:to_i).with(no_args).and_return(1)
|
|
217
|
-
do_create.should == 1
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
it 'should set the resource primary key if the model key size is 1 and the key is serial' do
|
|
221
|
-
@model.key.size.should == 1
|
|
222
|
-
@property.should_receive(:serial?).and_return(true)
|
|
223
|
-
@result.should_receive(:insert_id).and_return(777)
|
|
224
|
-
@property.should_receive(:set!).with(@resource, 777)
|
|
225
|
-
do_create.should == 1
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
[ :read_many, :read_one ].each do |method|
|
|
230
|
-
describe "##{method}" do
|
|
231
|
-
before do
|
|
232
|
-
@key = mock('key')
|
|
233
|
-
@model = mock('model', :key => @key, :storage_name => 'models', :relationships => {})
|
|
234
|
-
@primitive = mock('primitive')
|
|
235
|
-
@property = mock('property', :kind_of? => true, :model => @model, :field => 'property', :primitive => @primitive)
|
|
236
|
-
|
|
237
|
-
@child_model = @model
|
|
238
|
-
@parent_model = mock('parent model', :storage_name => 'parents')
|
|
239
|
-
@parent_property = mock('parent id', :kind_of? => true, :model => @parent_model, :field => 'id')
|
|
240
|
-
|
|
241
|
-
@child_key = [ @property ]
|
|
242
|
-
@parent_key = [ @parent_property ]
|
|
243
|
-
@relationship = mock('relationship', :child_model => @child_model, :parent_model => @parent_model, :child_key => @child_key, :parent_key => @parent_key)
|
|
244
|
-
@links = [ @relationship ]
|
|
245
|
-
|
|
246
|
-
@fields = [ @property ]
|
|
247
|
-
@bind_values = [ 'bind value' ]
|
|
248
|
-
@conditions = [ [ :eql, @property, @bind_values[0] ] ]
|
|
249
|
-
|
|
250
|
-
@direction = mock('direction', :property => @property, :direction => :desc)
|
|
251
|
-
@order = [ @direction ]
|
|
252
|
-
|
|
253
|
-
@query = mock('query', :model => @model, :kind_of? => true, :links => @links, :fields => @fields, :conditions => @conditions, :order => @order, :limit => 111, :offset => 222, :bind_values => @bind_values)
|
|
254
|
-
@query.should_receive(:unique?).with(no_args).and_return(false)
|
|
255
|
-
|
|
256
|
-
@reader = mock('reader', :close => true, :next! => false)
|
|
257
|
-
@command = mock('command', :set_types => nil, :execute_reader => @reader)
|
|
258
|
-
@connection = mock('connection', :close => true, :create_command => @command)
|
|
259
|
-
|
|
260
|
-
DataObjects::Connection.stub!(:new).and_return(@connection)
|
|
261
|
-
DataMapper::Query::Direction.stub!(:===).and_return(true)
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
if method == :read_one
|
|
265
|
-
before do
|
|
266
|
-
@query.should_receive(:limit).with(no_args).twice.and_return(1)
|
|
267
|
-
|
|
268
|
-
@values = @bind_values.dup
|
|
269
|
-
|
|
270
|
-
@reader.should_receive(:next!).with(no_args).and_return(true)
|
|
271
|
-
@reader.should_receive(:values).with(no_args).and_return(@values)
|
|
272
|
-
|
|
273
|
-
@resource = mock('resource')
|
|
274
|
-
@resource.should_receive(:kind_of?).with(DataMapper::Resource).any_number_of_times.and_return(true)
|
|
275
|
-
|
|
276
|
-
@model.should_receive(:load).with(@values, @query).and_return(@resource)
|
|
277
|
-
|
|
278
|
-
@statement = 'SELECT "models"."property" FROM "models" INNER JOIN "parents" ON ("parents"."id" = "models"."property") WHERE ("models"."property" = ?) ORDER BY "models"."property" DESC LIMIT 1 OFFSET 222'
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
define_method(:do_read) do
|
|
282
|
-
resource = @adapter.read_one(@query)
|
|
283
|
-
resource.should == @resource
|
|
284
|
-
resource
|
|
285
|
-
end
|
|
286
|
-
elsif method == :read_many
|
|
287
|
-
before do
|
|
288
|
-
@statement = 'SELECT "models"."property" FROM "models" INNER JOIN "parents" ON ("parents"."id" = "models"."property") WHERE ("models"."property" = ?) ORDER BY "models"."property" DESC LIMIT 111 OFFSET 222'
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
define_method(:do_read) do
|
|
292
|
-
collection = @adapter.read_many(@query)
|
|
293
|
-
collection.to_a
|
|
294
|
-
collection
|
|
295
|
-
end
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
it 'should use the bind values' do
|
|
299
|
-
@command.should_receive(:execute_reader).with(*@bind_values).and_return(@reader)
|
|
300
|
-
do_read
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
it 'should generate an SQL statement' do
|
|
304
|
-
@connection.should_receive(:create_command).with(@statement).and_return(@command)
|
|
305
|
-
do_read
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
it 'should generate an SQL statement with composite keys' do
|
|
309
|
-
other_property = mock('other property', :kind_of? => true)
|
|
310
|
-
other_property.should_receive(:field).with(:default).and_return('other')
|
|
311
|
-
other_property.should_receive(:model).with(no_args).and_return(@model)
|
|
312
|
-
|
|
313
|
-
other_value = 'other value'
|
|
314
|
-
@bind_values << other_value
|
|
315
|
-
@conditions << [ :eql, other_property, other_value ]
|
|
316
|
-
|
|
317
|
-
@statement = %[SELECT "models"."property" FROM "models" INNER JOIN "parents" ON ("parents"."id" = "models"."property") WHERE ("models"."property" = ?) AND ("models"."other" = ?) ORDER BY "models"."property" DESC LIMIT #{method == :read_one ? '1' : '111'} OFFSET 222]
|
|
318
|
-
@query.should_receive(:conditions).with(no_args).twice.and_return(@conditions)
|
|
319
|
-
|
|
320
|
-
@connection.should_receive(:create_command).with(@statement).and_return(@command)
|
|
321
|
-
|
|
322
|
-
do_read
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
it 'should set the return types to the property primitives' do
|
|
326
|
-
@command.should_receive(:set_types).with([ @primitive ])
|
|
327
|
-
do_read
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
it 'should close the reader' do
|
|
331
|
-
@reader.should_receive(:close).with(no_args)
|
|
332
|
-
do_read
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
it 'should close the connection' do
|
|
336
|
-
@connection.should_receive(:close).with(no_args)
|
|
337
|
-
do_read
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
if method == :read_one
|
|
341
|
-
it 'should return a DataMapper::Resource' do
|
|
342
|
-
do_read.should be_kind_of(DataMapper::Resource)
|
|
343
|
-
end
|
|
344
|
-
else
|
|
345
|
-
it 'should return a DataMapper::Collection' do
|
|
346
|
-
do_read.should be_kind_of(DataMapper::Collection)
|
|
347
|
-
end
|
|
348
|
-
end
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
describe '#update' do
|
|
353
|
-
before do
|
|
354
|
-
@result = mock('result', :to_i => 1)
|
|
355
|
-
|
|
356
|
-
@adapter.stub!(:execute).and_return(@result)
|
|
357
|
-
|
|
358
|
-
@values = %w[ new ]
|
|
359
|
-
@model = mock('model', :storage_name => 'models')
|
|
360
|
-
@property = mock('property', :kind_of? => true, :field => 'property')
|
|
361
|
-
@bind_values = [ 'bind value' ]
|
|
362
|
-
@conditions = [ [ :eql, @property, @bind_values[0] ] ]
|
|
363
|
-
@attributes = mock('attributes', :kind_of? => true, :empty? => false, :keys => [ @property ], :values => @values)
|
|
364
|
-
@query = mock('query', :kind_of? => true, :model => @model, :links => [], :conditions => @conditions, :bind_values => @bind_values)
|
|
365
|
-
@statement = 'UPDATE "models" SET "property" = ? WHERE ("property" = ?)'
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
def do_update
|
|
369
|
-
@adapter.update(@attributes, @query)
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
it 'should use the bind values' do
|
|
373
|
-
@attributes.should_receive(:values).with(no_args).and_return(@values)
|
|
374
|
-
@query.should_receive(:bind_values).with(no_args).and_return(@bind_values)
|
|
375
|
-
|
|
376
|
-
@adapter.should_receive(:execute).with(@statement, *@values + @bind_values).and_return(@result)
|
|
377
|
-
|
|
378
|
-
do_update.should == 1
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
it 'should generate an SQL statement' do
|
|
382
|
-
other_property = mock('other property', :kind_of? => true)
|
|
383
|
-
other_property.should_receive(:field).with(:default).and_return('other')
|
|
384
|
-
other_property.should_receive(:model).with(no_args).and_return(@model)
|
|
385
|
-
|
|
386
|
-
other_value = 'other value'
|
|
387
|
-
@bind_values << other_value
|
|
388
|
-
@conditions << [ :eql, other_property, other_value ]
|
|
389
|
-
|
|
390
|
-
@query.should_receive(:conditions).with(no_args).twice.and_return(@conditions)
|
|
391
|
-
|
|
392
|
-
@statement = 'UPDATE "models" SET "property" = ? WHERE ("property" = ?) AND ("other" = ?)'
|
|
393
|
-
@adapter.should_receive(:execute).with(@statement, *%w[ new ] + @bind_values).and_return(@result)
|
|
394
|
-
|
|
395
|
-
do_update.should == 1
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
it 'should return 0 if no rows updated' do
|
|
399
|
-
@result.should_receive(:to_i).with(no_args).and_return(0)
|
|
400
|
-
do_update.should == 0
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
it 'should return 1 if number of rows updated is 1' do
|
|
404
|
-
@result.should_receive(:to_i).with(no_args).and_return(1)
|
|
405
|
-
do_update.should == 1
|
|
406
|
-
end
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
describe '#delete' do
|
|
410
|
-
before do
|
|
411
|
-
@result = mock('result', :to_i => 1)
|
|
412
|
-
|
|
413
|
-
@adapter.stub!(:execute).and_return(@result)
|
|
414
|
-
|
|
415
|
-
@model = mock('model', :storage_name => 'models')
|
|
416
|
-
@property = mock('property', :kind_of? => true, :field => 'property')
|
|
417
|
-
@bind_values = [ 'bind value' ]
|
|
418
|
-
@conditions = [ [ :eql, @property, @bind_values[0] ] ]
|
|
419
|
-
@query = mock('query', :kind_of? => true, :model => @model, :links => [], :conditions => @conditions, :bind_values => @bind_values)
|
|
420
|
-
@resource = mock('resource', :to_query => @query)
|
|
421
|
-
@statement = 'DELETE FROM "models" WHERE ("property" = ?)'
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
def do_delete
|
|
425
|
-
@adapter.delete(@resource.to_query(@repository))
|
|
426
|
-
end
|
|
427
|
-
|
|
428
|
-
it 'should use the bind values' do
|
|
429
|
-
@query.should_receive(:bind_values).with(no_args).and_return(@bind_values)
|
|
430
|
-
|
|
431
|
-
@adapter.should_receive(:execute).with(@statement, *@bind_values).and_return(@result)
|
|
432
|
-
|
|
433
|
-
do_delete.should == 1
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
it 'should generate an SQL statement' do
|
|
437
|
-
other_property = mock('other property', :kind_of? => true)
|
|
438
|
-
other_property.should_receive(:field).with(:default).and_return('other')
|
|
439
|
-
other_property.should_receive(:model).with(no_args).and_return(@model)
|
|
440
|
-
|
|
441
|
-
other_value = 'other value'
|
|
442
|
-
@bind_values << other_value
|
|
443
|
-
@conditions << [ :eql, other_property, other_value ]
|
|
444
|
-
|
|
445
|
-
@query.should_receive(:conditions).with(no_args).twice.and_return(@conditions)
|
|
446
|
-
|
|
447
|
-
@statement = 'DELETE FROM "models" WHERE ("property" = ?) AND ("other" = ?)'
|
|
448
|
-
@adapter.should_receive(:execute).with(@statement, *@bind_values).and_return(@result)
|
|
449
|
-
|
|
450
|
-
do_delete.should == 1
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
it 'should return 0 if no rows deleted' do
|
|
454
|
-
@result.should_receive(:to_i).with(no_args).and_return(0)
|
|
455
|
-
do_delete.should == 0
|
|
456
|
-
end
|
|
457
|
-
|
|
458
|
-
it 'should return 1 if number of rows deleted is 1' do
|
|
459
|
-
@result.should_receive(:to_i).with(no_args).and_return(1)
|
|
460
|
-
do_delete.should == 1
|
|
461
|
-
end
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
describe "when upgrading tables" do
|
|
465
|
-
it "should raise NotImplementedError when #storage_exists? is called" do
|
|
466
|
-
lambda { @adapter.storage_exists?("cheeses") }.should raise_error(NotImplementedError)
|
|
467
|
-
end
|
|
468
|
-
|
|
469
|
-
describe "#upgrade_model_storage" do
|
|
470
|
-
it "should call #create_model_storage" do
|
|
471
|
-
@adapter.should_receive(:create_model_storage).with(repository, Cheese).and_return(true)
|
|
472
|
-
@adapter.upgrade_model_storage(repository, Cheese).should == Cheese.properties
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
it "should check if all properties of the model have columns if the table exists" do
|
|
476
|
-
@adapter.should_receive(:field_exists?).with("cheeses", "id").and_return(true)
|
|
477
|
-
@adapter.should_receive(:field_exists?).with("cheeses", "name").and_return(true)
|
|
478
|
-
@adapter.should_receive(:field_exists?).with("cheeses", "color").and_return(true)
|
|
479
|
-
@adapter.should_receive(:field_exists?).with("cheeses", "notes").and_return(true)
|
|
480
|
-
@adapter.should_receive(:storage_exists?).with("cheeses").and_return(true)
|
|
481
|
-
@adapter.upgrade_model_storage(repository, Cheese).should == []
|
|
482
|
-
end
|
|
483
|
-
|
|
484
|
-
it "should create and execute add column statements for columns that dont exist" do
|
|
485
|
-
@adapter.should_receive(:field_exists?).with("cheeses", "id").and_return(true)
|
|
486
|
-
@adapter.should_receive(:field_exists?).with("cheeses", "name").and_return(true)
|
|
487
|
-
@adapter.should_receive(:field_exists?).with("cheeses", "color").and_return(true)
|
|
488
|
-
@adapter.should_receive(:field_exists?).with("cheeses", "notes").and_return(false)
|
|
489
|
-
@adapter.should_receive(:storage_exists?).with("cheeses").and_return(true)
|
|
490
|
-
connection = mock("connection")
|
|
491
|
-
connection.should_receive(:close)
|
|
492
|
-
@adapter.should_receive(:create_connection).and_return(connection)
|
|
493
|
-
statement = mock("statement")
|
|
494
|
-
command = mock("command")
|
|
495
|
-
result = mock("result")
|
|
496
|
-
command.should_receive(:execute_non_query).and_return(result)
|
|
497
|
-
connection.should_receive(:create_command).with(statement).and_return(command)
|
|
498
|
-
@adapter.should_receive(:alter_table_add_column_statement).with("cheeses",
|
|
499
|
-
{
|
|
500
|
-
:nullable? => true,
|
|
501
|
-
:name => "notes",
|
|
502
|
-
:serial? => false,
|
|
503
|
-
:primitive => "VARCHAR",
|
|
504
|
-
:size => 100
|
|
505
|
-
}).and_return(statement)
|
|
506
|
-
@adapter.upgrade_model_storage(repository, Cheese).should == [Cheese.notes]
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
end
|
|
510
|
-
|
|
511
|
-
describe '#execute' do
|
|
512
|
-
before do
|
|
513
|
-
@mock_command = mock('Command', :execute_non_query => nil)
|
|
514
|
-
@mock_db = mock('DB Connection', :create_command => @mock_command, :close => true)
|
|
515
|
-
|
|
516
|
-
@adapter.stub!(:create_connection).and_return(@mock_db)
|
|
517
|
-
end
|
|
518
|
-
|
|
519
|
-
it 'should #create_command from the sql passed' do
|
|
520
|
-
@mock_db.should_receive(:create_command).with('SQL STRING').and_return(@mock_command)
|
|
521
|
-
@adapter.execute('SQL STRING')
|
|
522
|
-
end
|
|
523
|
-
|
|
524
|
-
it 'should pass any additional args to #execute_non_query' do
|
|
525
|
-
@mock_command.should_receive(:execute_non_query).with(:args)
|
|
526
|
-
@adapter.execute('SQL STRING', :args)
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
it 'should return the result of #execute_non_query' do
|
|
530
|
-
@mock_command.should_receive(:execute_non_query).and_return(:result_set)
|
|
531
|
-
|
|
532
|
-
@adapter.execute('SQL STRING').should == :result_set
|
|
533
|
-
end
|
|
534
|
-
|
|
535
|
-
it 'should log any errors, then re-raise them' do
|
|
536
|
-
@mock_command.should_receive(:execute_non_query).and_raise("Oh Noes!")
|
|
537
|
-
DataMapper.logger.should_receive(:error)
|
|
538
|
-
|
|
539
|
-
lambda { @adapter.execute('SQL STRING') }.should raise_error("Oh Noes!")
|
|
540
|
-
end
|
|
541
|
-
|
|
542
|
-
it 'should always close the db connection' do
|
|
543
|
-
@mock_command.should_receive(:execute_non_query).and_raise("Oh Noes!")
|
|
544
|
-
@mock_db.should_receive(:close)
|
|
545
|
-
|
|
546
|
-
lambda { @adapter.execute('SQL STRING') }.should raise_error("Oh Noes!")
|
|
547
|
-
end
|
|
548
|
-
end
|
|
549
|
-
|
|
550
|
-
describe '#query' do
|
|
551
|
-
before do
|
|
552
|
-
@mock_reader = mock('Reader', :fields => ['id', 'UserName', 'AGE'],
|
|
553
|
-
:values => [1, 'rando', 27],
|
|
554
|
-
:close => true)
|
|
555
|
-
@mock_command = mock('Command', :execute_reader => @mock_reader)
|
|
556
|
-
@mock_db = mock('DB Connection', :create_command => @mock_command, :close => true)
|
|
557
|
-
|
|
558
|
-
#make the while loop run exactly once
|
|
559
|
-
@mock_reader.stub!(:next!).and_return(true, nil)
|
|
560
|
-
@adapter.stub!(:create_connection).and_return(@mock_db)
|
|
561
|
-
end
|
|
562
|
-
|
|
563
|
-
it 'should #create_command from the sql passed' do
|
|
564
|
-
@mock_db.should_receive(:create_command).with('SQL STRING').and_return(@mock_command)
|
|
565
|
-
@adapter.query('SQL STRING')
|
|
566
|
-
end
|
|
567
|
-
|
|
568
|
-
it 'should pass any additional args to #execute_reader' do
|
|
569
|
-
@mock_command.should_receive(:execute_reader).with(:args).and_return(@mock_reader)
|
|
570
|
-
@adapter.query('SQL STRING', :args)
|
|
571
|
-
end
|
|
572
|
-
|
|
573
|
-
describe 'returning multiple fields' do
|
|
574
|
-
|
|
575
|
-
it 'should underscore the field names as members of the result struct' do
|
|
576
|
-
@mock_reader.should_receive(:fields).and_return(['id', 'UserName', 'AGE'])
|
|
577
|
-
|
|
578
|
-
result = @adapter.query('SQL STRING')
|
|
579
|
-
|
|
580
|
-
result.first.members.map { |m| m.to_s }.should == %w[ id user_name age ]
|
|
581
|
-
end
|
|
582
|
-
|
|
583
|
-
it 'should convert each row into the struct' do
|
|
584
|
-
@mock_reader.should_receive(:values).and_return([1, 'rando', 27])
|
|
585
|
-
|
|
586
|
-
@adapter.query('SQL STRING')
|
|
587
|
-
end
|
|
588
|
-
|
|
589
|
-
it 'should add the row structs into the results array' do
|
|
590
|
-
results = @adapter.query('SQL STRING')
|
|
591
|
-
|
|
592
|
-
results.should be_kind_of(Array)
|
|
593
|
-
|
|
594
|
-
row = results.first
|
|
595
|
-
row.should be_kind_of(Struct)
|
|
596
|
-
|
|
597
|
-
row.id.should == 1
|
|
598
|
-
row.user_name.should == 'rando'
|
|
599
|
-
row.age.should == 27
|
|
600
|
-
end
|
|
601
|
-
|
|
602
|
-
end
|
|
603
|
-
|
|
604
|
-
describe 'returning a single field' do
|
|
605
|
-
|
|
606
|
-
it 'should add the value to the results array' do
|
|
607
|
-
@mock_reader.should_receive(:fields).and_return(['username'])
|
|
608
|
-
@mock_reader.should_receive(:values).and_return(['rando'])
|
|
609
|
-
|
|
610
|
-
results = @adapter.query('SQL STRING')
|
|
611
|
-
|
|
612
|
-
results.should be_kind_of(Array)
|
|
613
|
-
results.first.should == 'rando'
|
|
614
|
-
end
|
|
615
|
-
|
|
616
|
-
end
|
|
617
|
-
|
|
618
|
-
it 'should log any errors, then re-raise them' do
|
|
619
|
-
@mock_command.should_receive(:execute_non_query).and_raise("Oh Noes!")
|
|
620
|
-
DataMapper.logger.should_receive(:error)
|
|
621
|
-
|
|
622
|
-
lambda { @adapter.execute('SQL STRING') }.should raise_error("Oh Noes!")
|
|
623
|
-
end
|
|
624
|
-
|
|
625
|
-
it 'should always close the db connection' do
|
|
626
|
-
@mock_command.should_receive(:execute_non_query).and_raise("Oh Noes!")
|
|
627
|
-
@mock_db.should_receive(:close)
|
|
628
|
-
|
|
629
|
-
lambda { @adapter.execute('SQL STRING') }.should raise_error("Oh Noes!")
|
|
630
|
-
end
|
|
631
|
-
end
|
|
632
|
-
end
|