datamapper-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 -39
- data/Manifest.txt +67 -76
- data/QUICKLINKS +1 -1
- data/README.txt +21 -15
- data/Rakefile +16 -15
- data/SPECS +2 -29
- data/TODO +1 -1
- data/dm-core.gemspec +11 -15
- data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
- 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/adapters.rb +135 -16
- 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 +560 -158
- data/lib/dm-core/collection.rb +1104 -381
- 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/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 +248 -0
- data/lib/dm-core/model/relationship.rb +335 -0
- data/lib/dm-core/model/scope.rb +90 -0
- data/lib/dm-core/model.rb +570 -369
- data/lib/dm-core/property.rb +753 -280
- data/lib/dm-core/property_set.rb +141 -98
- data/lib/dm-core/query/conditions/comparison.rb +814 -0
- data/lib/dm-core/query/conditions/operation.rb +247 -0
- data/lib/dm-core/query/direction.rb +43 -0
- data/lib/dm-core/query/operator.rb +42 -0
- data/lib/dm-core/query/path.rb +102 -0
- data/lib/dm-core/query/sort.rb +45 -0
- data/lib/dm-core/query.rb +974 -492
- data/lib/dm-core/repository.rb +147 -107
- data/lib/dm-core/resource.rb +644 -429
- 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 +20 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/equalizer.rb +23 -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/lib/dm-core.rb +106 -110
- 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/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 +1723 -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/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 +72 -93
- data/lib/dm-core/associations/relationship_chain.rb +0 -81
- data/lib/dm-core/associations.rb +0 -207
- 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/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/support.rb +0 -7
- 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
|
@@ -1,189 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
require DataMapper.root / 'lib' / 'dm-core' / 'adapters' / 'data_objects_adapter'
|
|
2
|
+
|
|
2
3
|
require 'do_postgres'
|
|
3
4
|
|
|
4
5
|
module DataMapper
|
|
5
6
|
module Adapters
|
|
6
7
|
class PostgresAdapter < DataObjectsAdapter
|
|
7
|
-
module SQL
|
|
8
|
+
module SQL #:nodoc:
|
|
8
9
|
private
|
|
9
10
|
|
|
11
|
+
# TODO: document
|
|
12
|
+
# @api private
|
|
10
13
|
def supports_returning?
|
|
11
14
|
true
|
|
12
15
|
end
|
|
13
16
|
end #module SQL
|
|
14
17
|
|
|
15
18
|
include SQL
|
|
16
|
-
|
|
17
|
-
# TODO: move to dm-more/dm-migrations (if possible)
|
|
18
|
-
module Migration
|
|
19
|
-
# TODO: move to dm-more/dm-migrations (if possible)
|
|
20
|
-
def storage_exists?(storage_name)
|
|
21
|
-
statement = <<-SQL.compress_lines
|
|
22
|
-
SELECT COUNT(*)
|
|
23
|
-
FROM "information_schema"."tables"
|
|
24
|
-
WHERE "table_type" = 'BASE TABLE'
|
|
25
|
-
AND "table_schema" = current_schema()
|
|
26
|
-
AND "table_name" = ?
|
|
27
|
-
SQL
|
|
28
|
-
|
|
29
|
-
query(statement, storage_name).first > 0
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# TODO: move to dm-more/dm-migrations (if possible)
|
|
33
|
-
def field_exists?(storage_name, column_name)
|
|
34
|
-
statement = <<-SQL.compress_lines
|
|
35
|
-
SELECT COUNT(*)
|
|
36
|
-
FROM "information_schema"."columns"
|
|
37
|
-
WHERE "table_schema" = current_schema()
|
|
38
|
-
AND "table_name" = ?
|
|
39
|
-
AND "column_name" = ?
|
|
40
|
-
SQL
|
|
41
|
-
|
|
42
|
-
query(statement, storage_name, column_name).first > 0
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# TODO: move to dm-more/dm-migrations
|
|
46
|
-
def upgrade_model_storage(repository, model)
|
|
47
|
-
add_sequences(repository, model)
|
|
48
|
-
super
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# TODO: move to dm-more/dm-migrations
|
|
52
|
-
def create_model_storage(repository, model)
|
|
53
|
-
add_sequences(repository, model)
|
|
54
|
-
without_notices { super }
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# TODO: move to dm-more/dm-migrations
|
|
58
|
-
def destroy_model_storage(repository, model)
|
|
59
|
-
return true unless storage_exists?(model.storage_name(repository.name))
|
|
60
|
-
success = without_notices { super }
|
|
61
|
-
model.properties(repository.name).each do |property|
|
|
62
|
-
drop_sequence(repository, property) if property.serial?
|
|
63
|
-
end
|
|
64
|
-
success
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
protected
|
|
68
|
-
|
|
69
|
-
# TODO: move to dm-more/dm-migrations
|
|
70
|
-
def create_sequence(repository, property)
|
|
71
|
-
return if sequence_exists?(repository, property)
|
|
72
|
-
execute(create_sequence_statement(repository, property))
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# TODO: move to dm-more/dm-migrations
|
|
76
|
-
def drop_sequence(repository, property)
|
|
77
|
-
without_notices { execute(drop_sequence_statement(repository, property)) }
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
module SQL
|
|
81
|
-
private
|
|
82
|
-
|
|
83
|
-
# TODO: move to dm-more/dm-migrations
|
|
84
|
-
def drop_table_statement(repository, model)
|
|
85
|
-
"DROP TABLE #{quote_table_name(model.storage_name(repository.name))}"
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# TODO: move to dm-more/dm-migrations
|
|
89
|
-
def without_notices
|
|
90
|
-
# execute the block with NOTICE messages disabled
|
|
91
|
-
begin
|
|
92
|
-
execute('SET client_min_messages = warning')
|
|
93
|
-
yield
|
|
94
|
-
ensure
|
|
95
|
-
execute('RESET client_min_messages')
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# TODO: move to dm-more/dm-migrations
|
|
100
|
-
def add_sequences(repository, model)
|
|
101
|
-
model.properties(repository.name).each do |property|
|
|
102
|
-
create_sequence(repository, property) if property.serial?
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# TODO: move to dm-more/dm-migrations
|
|
107
|
-
def sequence_name(repository, property)
|
|
108
|
-
"#{property.model.storage_name(repository.name)}_#{property.field(repository.name)}_seq"
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# TODO: move to dm-more/dm-migrations
|
|
112
|
-
def sequence_exists?(repository, property)
|
|
113
|
-
statement = <<-EOS.compress_lines
|
|
114
|
-
SELECT COUNT(*)
|
|
115
|
-
FROM "information_schema"."sequences"
|
|
116
|
-
WHERE "sequence_name" = ?
|
|
117
|
-
AND "sequence_schema" = current_schema()
|
|
118
|
-
EOS
|
|
119
|
-
|
|
120
|
-
query(statement, sequence_name(repository, property)).first > 0
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# TODO: move to dm-more/dm-migrations
|
|
124
|
-
def create_sequence_statement(repository, property)
|
|
125
|
-
"CREATE SEQUENCE #{quote_column_name(sequence_name(repository, property))}"
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# TODO: move to dm-more/dm-migrations
|
|
129
|
-
def drop_sequence_statement(repository, property)
|
|
130
|
-
"DROP SEQUENCE IF EXISTS #{quote_column_name(sequence_name(repository, property))}"
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# TODO: move to dm-more/dm-migrations
|
|
134
|
-
def property_schema_statement(schema)
|
|
135
|
-
statement = super
|
|
136
|
-
|
|
137
|
-
if schema.has_key?(:sequence_name)
|
|
138
|
-
statement << " DEFAULT nextval('#{schema[:sequence_name]}') NOT NULL"
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
statement
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
# TODO: move to dm-more/dm-migrations
|
|
145
|
-
def property_schema_hash(repository, property)
|
|
146
|
-
schema = super
|
|
147
|
-
|
|
148
|
-
if property.serial?
|
|
149
|
-
schema.delete(:default) # the sequence will be the default
|
|
150
|
-
schema[:sequence_name] = sequence_name(repository, property)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# TODO: see if TypeMap can be updated to set specific attributes to nil
|
|
154
|
-
# for different adapters. precision/scale are perfect examples for
|
|
155
|
-
# Postgres floats
|
|
156
|
-
|
|
157
|
-
# Postgres does not support precision and scale for Float
|
|
158
|
-
if property.primitive == Float
|
|
159
|
-
schema.delete(:precision)
|
|
160
|
-
schema.delete(:scale)
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
schema
|
|
164
|
-
end
|
|
165
|
-
end # module SQL
|
|
166
|
-
|
|
167
|
-
include SQL
|
|
168
|
-
|
|
169
|
-
module ClassMethods
|
|
170
|
-
# TypeMap for PostgreSQL databases.
|
|
171
|
-
#
|
|
172
|
-
# @return <DataMapper::TypeMap> default TypeMap for PostgreSQL databases.
|
|
173
|
-
#
|
|
174
|
-
# TODO: move to dm-more/dm-migrations
|
|
175
|
-
def type_map
|
|
176
|
-
@type_map ||= TypeMap.new(super) do |tm|
|
|
177
|
-
tm.map(DateTime).to('TIMESTAMP')
|
|
178
|
-
tm.map(Integer).to('INT4')
|
|
179
|
-
tm.map(Float).to('FLOAT8')
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end # module ClassMethods
|
|
183
|
-
end # module Migration
|
|
184
|
-
|
|
185
|
-
include Migration
|
|
186
|
-
extend Migration::ClassMethods
|
|
187
19
|
end # class PostgresAdapter
|
|
20
|
+
|
|
21
|
+
const_added(:PostgresAdapter)
|
|
188
22
|
end # module Adapters
|
|
189
23
|
end # module DataMapper
|
|
@@ -1,105 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
require DataMapper.root / 'lib' / 'dm-core' / 'adapters' / 'data_objects_adapter'
|
|
2
|
+
|
|
2
3
|
require 'do_sqlite3'
|
|
3
4
|
|
|
4
5
|
module DataMapper
|
|
5
6
|
module Adapters
|
|
6
7
|
class Sqlite3Adapter < DataObjectsAdapter
|
|
7
|
-
module SQL
|
|
8
|
-
private
|
|
9
|
-
|
|
10
|
-
def quote_column_value(column_value)
|
|
11
|
-
case column_value
|
|
12
|
-
when TrueClass then quote_column_value('t')
|
|
13
|
-
when FalseClass then quote_column_value('f')
|
|
14
|
-
else
|
|
15
|
-
super
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end # module SQL
|
|
19
|
-
|
|
20
|
-
include SQL
|
|
21
|
-
|
|
22
|
-
# TODO: move to dm-more/dm-migrations (if possible)
|
|
23
|
-
module Migration
|
|
24
|
-
# TODO: move to dm-more/dm-migrations (if possible)
|
|
25
|
-
def storage_exists?(storage_name)
|
|
26
|
-
query_table(storage_name).size > 0
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# TODO: move to dm-more/dm-migrations (if possible)
|
|
30
|
-
def field_exists?(storage_name, column_name)
|
|
31
|
-
query_table(storage_name).any? do |row|
|
|
32
|
-
row.name == column_name
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
# TODO: move to dm-more/dm-migrations (if possible)
|
|
39
|
-
def query_table(table_name)
|
|
40
|
-
query('PRAGMA table_info(?)', table_name)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
module SQL
|
|
44
|
-
# private ## This cannot be private for current migrations
|
|
45
|
-
|
|
46
|
-
# TODO: move to dm-more/dm-migrations
|
|
47
|
-
def supports_serial?
|
|
48
|
-
sqlite_version >= '3.1.0'
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# TODO: move to dm-more/dm-migrations
|
|
52
|
-
def create_table_statement(repository, model)
|
|
53
|
-
statement = <<-EOS.compress_lines
|
|
54
|
-
CREATE TABLE #{quote_table_name(model.storage_name(repository.name))}
|
|
55
|
-
(#{model.properties_with_subclasses(repository.name).map { |p| property_schema_statement(property_schema_hash(repository, p)) } * ', '}
|
|
56
|
-
EOS
|
|
57
|
-
|
|
58
|
-
# skip adding the primary key if one of the columns is serial. In
|
|
59
|
-
# SQLite the serial column must be the primary key, so it has already
|
|
60
|
-
# been defined
|
|
61
|
-
unless model.properties(repository.name).any? { |p| p.serial? }
|
|
62
|
-
if (key = model.properties(repository.name).key).any?
|
|
63
|
-
statement << ", PRIMARY KEY(#{key.map { |p| quote_column_name(p.field(repository.name)) } * ', '})"
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
statement << ')'
|
|
68
|
-
statement
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# TODO: move to dm-more/dm-migrations
|
|
72
|
-
def property_schema_statement(schema)
|
|
73
|
-
statement = super
|
|
74
|
-
statement << ' PRIMARY KEY AUTOINCREMENT' if supports_serial? && schema[:serial?]
|
|
75
|
-
statement
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# TODO: move to dm-more/dm-migrations
|
|
79
|
-
def sqlite_version
|
|
80
|
-
@sqlite_version ||= query('SELECT sqlite_version(*)').first
|
|
81
|
-
end
|
|
82
|
-
end # module SQL
|
|
83
|
-
|
|
84
|
-
include SQL
|
|
85
|
-
|
|
86
|
-
module ClassMethods
|
|
87
|
-
# TypeMap for SQLite 3 databases.
|
|
88
|
-
#
|
|
89
|
-
# @return <DataMapper::TypeMap> default TypeMap for SQLite 3 databases.
|
|
90
|
-
#
|
|
91
|
-
# TODO: move to dm-more/dm-migrations
|
|
92
|
-
def type_map
|
|
93
|
-
@type_map ||= TypeMap.new(super) do |tm|
|
|
94
|
-
tm.map(Integer).to('INTEGER')
|
|
95
|
-
tm.map(Class).to('VARCHAR')
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end # module ClassMethods
|
|
99
|
-
end # module Migration
|
|
100
|
-
|
|
101
|
-
include Migration
|
|
102
|
-
extend Migration::ClassMethods
|
|
103
8
|
end # class Sqlite3Adapter
|
|
9
|
+
|
|
10
|
+
const_added(:Sqlite3Adapter)
|
|
104
11
|
end # module Adapters
|
|
105
12
|
end # module DataMapper
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
|
|
4
|
+
module DataMapper
|
|
5
|
+
module Adapters
|
|
6
|
+
class YamlAdapter < AbstractAdapter
|
|
7
|
+
# TODO: document
|
|
8
|
+
# @api semipublic
|
|
9
|
+
def create(resources)
|
|
10
|
+
update_records(resources.first.model) do |records|
|
|
11
|
+
resources.each do |resource|
|
|
12
|
+
initialize_serial(resource, records.size.succ)
|
|
13
|
+
records << resource.attributes(:field)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# TODO: document
|
|
19
|
+
# @api semipublic
|
|
20
|
+
def read(query)
|
|
21
|
+
query.filter_records(records_for(query.model).dup)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# TODO: document
|
|
25
|
+
# @api semipublic
|
|
26
|
+
def update(attributes, collection)
|
|
27
|
+
attributes = attributes_as_fields(attributes)
|
|
28
|
+
|
|
29
|
+
update_records(collection.model) do |records|
|
|
30
|
+
records_to_update = collection.query.filter_records(records.dup)
|
|
31
|
+
records_to_update.each { |resource| resource.update(attributes) }.size
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# TODO: document
|
|
36
|
+
# @api semipublic
|
|
37
|
+
def delete(collection)
|
|
38
|
+
update_records(collection.model) do |records|
|
|
39
|
+
records_to_delete = collection.query.filter_records(records.dup)
|
|
40
|
+
records.replace(records - records_to_delete)
|
|
41
|
+
records_to_delete.size
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# TODO: document
|
|
48
|
+
# @api semipublic
|
|
49
|
+
def initialize(name, options = {})
|
|
50
|
+
super
|
|
51
|
+
(@path = Pathname(@options[:path]).freeze).mkpath
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Retrieves all records for a model and yeilds them to a block.
|
|
55
|
+
#
|
|
56
|
+
# The block should make any changes to the records in-place. After
|
|
57
|
+
# the block executes all the records are dumped back to the file.
|
|
58
|
+
#
|
|
59
|
+
# @param [Model, #to_s] model
|
|
60
|
+
# Used to determine which file to read/write to
|
|
61
|
+
#
|
|
62
|
+
# @yieldparam [Hash]
|
|
63
|
+
# A hash of record.key => record pairs retrieved from the file
|
|
64
|
+
#
|
|
65
|
+
# @api private
|
|
66
|
+
def update_records(model)
|
|
67
|
+
records = records_for(model)
|
|
68
|
+
result = yield records
|
|
69
|
+
write_records(model, records)
|
|
70
|
+
result
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Read all records from a file for a model
|
|
74
|
+
#
|
|
75
|
+
# @param [#storage_name] model
|
|
76
|
+
# The model/name to retieve records for
|
|
77
|
+
#
|
|
78
|
+
# @api private
|
|
79
|
+
def records_for(model)
|
|
80
|
+
file = yaml_file(model)
|
|
81
|
+
file.readable? && YAML.load_file(file) || []
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Writes all records to a file
|
|
85
|
+
#
|
|
86
|
+
# @param [#storage_name] model
|
|
87
|
+
# The model/name to write the records for
|
|
88
|
+
#
|
|
89
|
+
# @param [Hash] records
|
|
90
|
+
# A hash of record.key => record pairs to be written
|
|
91
|
+
#
|
|
92
|
+
# @api private
|
|
93
|
+
def write_records(model, records)
|
|
94
|
+
yaml_file(model).open('w') do |fh|
|
|
95
|
+
YAML.dump(records, fh)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Given a model, gives the filename to be used for record storage
|
|
100
|
+
#
|
|
101
|
+
# @example
|
|
102
|
+
# yaml_file(Article) #=> "/path/to/files/articles.yml"
|
|
103
|
+
#
|
|
104
|
+
# @param [#storage_name] model
|
|
105
|
+
# The model to be used to determine the file name.
|
|
106
|
+
#
|
|
107
|
+
# @api private
|
|
108
|
+
def yaml_file(model)
|
|
109
|
+
@path / "#{model.storage_name(name)}.yml"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end # class YamlAdapter
|
|
113
|
+
|
|
114
|
+
const_added(:YamlAdapter)
|
|
115
|
+
end # module Adapters
|
|
116
|
+
end # module DataMapper
|
data/lib/dm-core/adapters.rb
CHANGED
|
@@ -1,16 +1,135 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Adapters
|
|
3
|
+
extend Chainable
|
|
4
|
+
extend Extlib::Assertions
|
|
5
|
+
|
|
6
|
+
# Set up an adapter for a storage engine
|
|
7
|
+
#
|
|
8
|
+
# @see DataMapper.setup
|
|
9
|
+
#
|
|
10
|
+
# @api private
|
|
11
|
+
def self.new(repository_name, options)
|
|
12
|
+
options = normalize_options(options)
|
|
13
|
+
adapter_class(options[:adapter]).new(repository_name, options)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
# Normalize the arguments passed to new()
|
|
20
|
+
#
|
|
21
|
+
# Turns options hash or connection URI into the options hash used
|
|
22
|
+
# by the adapter.
|
|
23
|
+
#
|
|
24
|
+
# @param [Hash, Addressable::URI, String] options
|
|
25
|
+
# the options to be normalized
|
|
26
|
+
#
|
|
27
|
+
# @return [Mash]
|
|
28
|
+
# the options normalized as a Mash
|
|
29
|
+
#
|
|
30
|
+
# @api private
|
|
31
|
+
def normalize_options(options)
|
|
32
|
+
case options
|
|
33
|
+
when Hash then normalize_options_hash(options)
|
|
34
|
+
when Addressable::URI then normalize_options_uri(options)
|
|
35
|
+
when String then normalize_options_string(options)
|
|
36
|
+
else
|
|
37
|
+
assert_kind_of 'options', options, Hash, Addressable::URI, String
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Normalize Hash options into a Mash
|
|
42
|
+
#
|
|
43
|
+
# @param [Hash] hash
|
|
44
|
+
# the hash to be normalized
|
|
45
|
+
#
|
|
46
|
+
# @return [Mash]
|
|
47
|
+
# the options normalized as a Mash
|
|
48
|
+
#
|
|
49
|
+
# @api private
|
|
50
|
+
def normalize_options_hash(hash)
|
|
51
|
+
hash.to_mash
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Normalize Addressable::URI options into a Mash
|
|
55
|
+
#
|
|
56
|
+
# @param [Addressable::URI] uri
|
|
57
|
+
# the uri to be normalized
|
|
58
|
+
#
|
|
59
|
+
# @return [Mash]
|
|
60
|
+
# the options normalized as a Mash
|
|
61
|
+
#
|
|
62
|
+
# @api private
|
|
63
|
+
def normalize_options_uri(uri)
|
|
64
|
+
options = normalize_options_hash(uri.to_hash)
|
|
65
|
+
|
|
66
|
+
# Extract the name/value pairs from the query portion of the
|
|
67
|
+
# connection uri, and set them as options directly.
|
|
68
|
+
if options[:query]
|
|
69
|
+
options.update(uri.query_values)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
options[:adapter] = options[:scheme]
|
|
73
|
+
|
|
74
|
+
options
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Normalize String options into a Mash
|
|
78
|
+
#
|
|
79
|
+
# @param [String] string
|
|
80
|
+
# the string to be normalized
|
|
81
|
+
#
|
|
82
|
+
# @return [Mash]
|
|
83
|
+
# the options normalized as a Mash
|
|
84
|
+
#
|
|
85
|
+
# @api private
|
|
86
|
+
def normalize_options_string(string)
|
|
87
|
+
normalize_options_uri(Addressable::URI.parse(string))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Return the adapter class constant
|
|
91
|
+
#
|
|
92
|
+
# @param [Symbol] name
|
|
93
|
+
# the name of the adapter
|
|
94
|
+
#
|
|
95
|
+
# @return [Class]
|
|
96
|
+
# the AbstractAdapter subclass
|
|
97
|
+
#
|
|
98
|
+
# @api private
|
|
99
|
+
def adapter_class(name)
|
|
100
|
+
class_name = (Extlib::Inflection.camelize(name) << 'Adapter').to_sym
|
|
101
|
+
load_adapter(name) unless const_defined?(class_name)
|
|
102
|
+
const_get(class_name)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Require the adapter library
|
|
106
|
+
#
|
|
107
|
+
# @param [String, Symbol] name
|
|
108
|
+
# the name of the adapter
|
|
109
|
+
#
|
|
110
|
+
# @return [Boolean]
|
|
111
|
+
# true if the adapter is loaded
|
|
112
|
+
#
|
|
113
|
+
# @api private
|
|
114
|
+
def load_adapter(name)
|
|
115
|
+
assert_kind_of 'name', name, String, Symbol
|
|
116
|
+
|
|
117
|
+
lib = "#{name}_adapter"
|
|
118
|
+
file = DataMapper.root / 'lib' / 'dm-core' / 'adapters' / "#{lib}.rb"
|
|
119
|
+
|
|
120
|
+
if file.file?
|
|
121
|
+
require file
|
|
122
|
+
else
|
|
123
|
+
require lib
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
extendable do
|
|
129
|
+
# TODO: document
|
|
130
|
+
# @api private
|
|
131
|
+
def const_added(const_name)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end # module Adapters
|
|
135
|
+
end # module DataMapper
|