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.
Files changed (192) hide show
  1. data/.autotest +17 -14
  2. data/.gitignore +3 -1
  3. data/FAQ +6 -5
  4. data/History.txt +5 -39
  5. data/Manifest.txt +67 -76
  6. data/QUICKLINKS +1 -1
  7. data/README.txt +21 -15
  8. data/Rakefile +16 -15
  9. data/SPECS +2 -29
  10. data/TODO +1 -1
  11. data/dm-core.gemspec +11 -15
  12. data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
  13. data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
  14. data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
  15. data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
  16. data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
  17. data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
  18. data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
  19. data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
  20. data/lib/dm-core/adapters.rb +135 -16
  21. data/lib/dm-core/associations/many_to_many.rb +372 -90
  22. data/lib/dm-core/associations/many_to_one.rb +220 -73
  23. data/lib/dm-core/associations/one_to_many.rb +319 -255
  24. data/lib/dm-core/associations/one_to_one.rb +66 -53
  25. data/lib/dm-core/associations/relationship.rb +560 -158
  26. data/lib/dm-core/collection.rb +1104 -381
  27. data/lib/dm-core/core_ext/kernel.rb +12 -0
  28. data/lib/dm-core/core_ext/symbol.rb +10 -0
  29. data/lib/dm-core/identity_map.rb +4 -34
  30. data/lib/dm-core/migrations.rb +1283 -0
  31. data/lib/dm-core/model/descendant_set.rb +81 -0
  32. data/lib/dm-core/model/hook.rb +45 -0
  33. data/lib/dm-core/model/is.rb +32 -0
  34. data/lib/dm-core/model/property.rb +248 -0
  35. data/lib/dm-core/model/relationship.rb +335 -0
  36. data/lib/dm-core/model/scope.rb +90 -0
  37. data/lib/dm-core/model.rb +570 -369
  38. data/lib/dm-core/property.rb +753 -280
  39. data/lib/dm-core/property_set.rb +141 -98
  40. data/lib/dm-core/query/conditions/comparison.rb +814 -0
  41. data/lib/dm-core/query/conditions/operation.rb +247 -0
  42. data/lib/dm-core/query/direction.rb +43 -0
  43. data/lib/dm-core/query/operator.rb +42 -0
  44. data/lib/dm-core/query/path.rb +102 -0
  45. data/lib/dm-core/query/sort.rb +45 -0
  46. data/lib/dm-core/query.rb +974 -492
  47. data/lib/dm-core/repository.rb +147 -107
  48. data/lib/dm-core/resource.rb +644 -429
  49. data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
  50. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
  51. data/lib/dm-core/support/chainable.rb +20 -0
  52. data/lib/dm-core/support/deprecate.rb +12 -0
  53. data/lib/dm-core/support/equalizer.rb +23 -0
  54. data/lib/dm-core/support/logger.rb +13 -0
  55. data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
  56. data/lib/dm-core/transaction.rb +333 -92
  57. data/lib/dm-core/type.rb +98 -60
  58. data/lib/dm-core/types/boolean.rb +1 -1
  59. data/lib/dm-core/types/discriminator.rb +34 -20
  60. data/lib/dm-core/types/object.rb +7 -4
  61. data/lib/dm-core/types/paranoid_boolean.rb +11 -9
  62. data/lib/dm-core/types/paranoid_datetime.rb +11 -9
  63. data/lib/dm-core/types/serial.rb +3 -3
  64. data/lib/dm-core/types/text.rb +3 -4
  65. data/lib/dm-core/version.rb +1 -1
  66. data/lib/dm-core.rb +106 -110
  67. data/script/performance.rb +102 -109
  68. data/script/profile.rb +169 -38
  69. data/spec/lib/adapter_helpers.rb +105 -0
  70. data/spec/lib/collection_helpers.rb +18 -0
  71. data/spec/lib/counter_adapter.rb +34 -0
  72. data/spec/lib/pending_helpers.rb +27 -0
  73. data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
  74. data/spec/public/associations/many_to_many_spec.rb +193 -0
  75. data/spec/public/associations/many_to_one_spec.rb +73 -0
  76. data/spec/public/associations/one_to_many_spec.rb +77 -0
  77. data/spec/public/associations/one_to_one_spec.rb +156 -0
  78. data/spec/public/collection_spec.rb +65 -0
  79. data/spec/public/model/relationship_spec.rb +924 -0
  80. data/spec/public/model_spec.rb +159 -0
  81. data/spec/public/property_spec.rb +829 -0
  82. data/spec/public/resource_spec.rb +71 -0
  83. data/spec/public/sel_spec.rb +44 -0
  84. data/spec/public/setup_spec.rb +145 -0
  85. data/spec/public/shared/association_collection_shared_spec.rb +317 -0
  86. data/spec/public/shared/collection_shared_spec.rb +1723 -0
  87. data/spec/public/shared/finder_shared_spec.rb +1619 -0
  88. data/spec/public/shared/resource_shared_spec.rb +924 -0
  89. data/spec/public/shared/sel_shared_spec.rb +112 -0
  90. data/spec/public/transaction_spec.rb +129 -0
  91. data/spec/public/types/discriminator_spec.rb +130 -0
  92. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  93. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  94. data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
  95. data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
  96. data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
  97. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
  98. data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
  99. data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
  100. data/spec/semipublic/associations/relationship_spec.rb +194 -0
  101. data/spec/semipublic/associations_spec.rb +177 -0
  102. data/spec/semipublic/collection_spec.rb +142 -0
  103. data/spec/semipublic/property_spec.rb +61 -0
  104. data/spec/semipublic/query/conditions_spec.rb +528 -0
  105. data/spec/semipublic/query/path_spec.rb +443 -0
  106. data/spec/semipublic/query_spec.rb +2626 -0
  107. data/spec/semipublic/resource_spec.rb +47 -0
  108. data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
  109. data/spec/spec.opts +3 -1
  110. data/spec/spec_helper.rb +80 -57
  111. data/tasks/ci.rb +19 -31
  112. data/tasks/dm.rb +43 -48
  113. data/tasks/doc.rb +8 -11
  114. data/tasks/gemspec.rb +5 -5
  115. data/tasks/hoe.rb +15 -16
  116. data/tasks/install.rb +8 -10
  117. metadata +72 -93
  118. data/lib/dm-core/associations/relationship_chain.rb +0 -81
  119. data/lib/dm-core/associations.rb +0 -207
  120. data/lib/dm-core/auto_migrations.rb +0 -105
  121. data/lib/dm-core/dependency_queue.rb +0 -32
  122. data/lib/dm-core/hook.rb +0 -11
  123. data/lib/dm-core/is.rb +0 -16
  124. data/lib/dm-core/logger.rb +0 -232
  125. data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
  126. data/lib/dm-core/migrator.rb +0 -29
  127. data/lib/dm-core/scope.rb +0 -58
  128. data/lib/dm-core/support/array.rb +0 -13
  129. data/lib/dm-core/support/assertions.rb +0 -8
  130. data/lib/dm-core/support/errors.rb +0 -23
  131. data/lib/dm-core/support/kernel.rb +0 -11
  132. data/lib/dm-core/support/symbol.rb +0 -41
  133. data/lib/dm-core/support.rb +0 -7
  134. data/lib/dm-core/type_map.rb +0 -80
  135. data/lib/dm-core/types.rb +0 -19
  136. data/script/all +0 -4
  137. data/spec/integration/association_spec.rb +0 -1382
  138. data/spec/integration/association_through_spec.rb +0 -203
  139. data/spec/integration/associations/many_to_many_spec.rb +0 -449
  140. data/spec/integration/associations/many_to_one_spec.rb +0 -163
  141. data/spec/integration/associations/one_to_many_spec.rb +0 -188
  142. data/spec/integration/auto_migrations_spec.rb +0 -413
  143. data/spec/integration/collection_spec.rb +0 -1073
  144. data/spec/integration/data_objects_adapter_spec.rb +0 -32
  145. data/spec/integration/dependency_queue_spec.rb +0 -46
  146. data/spec/integration/model_spec.rb +0 -197
  147. data/spec/integration/mysql_adapter_spec.rb +0 -85
  148. data/spec/integration/postgres_adapter_spec.rb +0 -731
  149. data/spec/integration/property_spec.rb +0 -253
  150. data/spec/integration/query_spec.rb +0 -514
  151. data/spec/integration/repository_spec.rb +0 -61
  152. data/spec/integration/resource_spec.rb +0 -513
  153. data/spec/integration/sqlite3_adapter_spec.rb +0 -352
  154. data/spec/integration/sti_spec.rb +0 -273
  155. data/spec/integration/strategic_eager_loading_spec.rb +0 -156
  156. data/spec/integration/transaction_spec.rb +0 -75
  157. data/spec/integration/type_spec.rb +0 -275
  158. data/spec/lib/logging_helper.rb +0 -18
  159. data/spec/lib/mock_adapter.rb +0 -27
  160. data/spec/lib/model_loader.rb +0 -100
  161. data/spec/lib/publicize_methods.rb +0 -28
  162. data/spec/models/content.rb +0 -16
  163. data/spec/models/vehicles.rb +0 -34
  164. data/spec/models/zoo.rb +0 -48
  165. data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
  166. data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
  167. data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
  168. data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
  169. data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
  170. data/spec/unit/associations/many_to_many_spec.rb +0 -32
  171. data/spec/unit/associations/many_to_one_spec.rb +0 -159
  172. data/spec/unit/associations/one_to_many_spec.rb +0 -393
  173. data/spec/unit/associations/one_to_one_spec.rb +0 -7
  174. data/spec/unit/associations/relationship_spec.rb +0 -71
  175. data/spec/unit/associations_spec.rb +0 -242
  176. data/spec/unit/auto_migrations_spec.rb +0 -111
  177. data/spec/unit/collection_spec.rb +0 -182
  178. data/spec/unit/data_mapper_spec.rb +0 -35
  179. data/spec/unit/identity_map_spec.rb +0 -126
  180. data/spec/unit/is_spec.rb +0 -80
  181. data/spec/unit/migrator_spec.rb +0 -33
  182. data/spec/unit/model_spec.rb +0 -321
  183. data/spec/unit/naming_conventions_spec.rb +0 -36
  184. data/spec/unit/property_set_spec.rb +0 -90
  185. data/spec/unit/property_spec.rb +0 -753
  186. data/spec/unit/query_spec.rb +0 -571
  187. data/spec/unit/repository_spec.rb +0 -93
  188. data/spec/unit/resource_spec.rb +0 -649
  189. data/spec/unit/scope_spec.rb +0 -142
  190. data/spec/unit/transaction_spec.rb +0 -493
  191. data/spec/unit/type_map_spec.rb +0 -114
  192. data/spec/unit/type_spec.rb +0 -119
@@ -1,189 +1,23 @@
1
- gem 'do_postgres', '~>0.9.12'
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
- gem 'do_sqlite3', '~>0.9.12'
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
@@ -1,16 +1,135 @@
1
- dir = Pathname(__FILE__).dirname.expand_path / 'adapters'
2
-
3
- require dir / 'abstract_adapter'
4
- require dir / 'in_memory_adapter'
5
-
6
- # NOTE: this is a temporary work-around to the load error problems,
7
- # and is better fixed in dm-core/next. The main reason the fix is
8
- # not applied in dm-core/master is because the change is non-trivial.
9
-
10
- %w[ data_objects sqlite3 mysql postgres ].each do |gem|
11
- begin
12
- require dir / "#{gem}_adapter"
13
- rescue LoadError, Gem::Exception
14
- # ignore it
15
- end
16
- end
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