mack-data_mapper 0.8.1 → 0.8.2

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 (166) hide show
  1. data/lib/gems/addressable-2.0.0/lib/addressable/idna.rb +4867 -0
  2. data/lib/gems/addressable-2.0.0/lib/addressable/uri.rb +2469 -0
  3. data/lib/gems/addressable-2.0.0/lib/addressable/version.rb +35 -0
  4. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/adapters/data_objects_adapter.rb +85 -0
  5. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/aggregate_functions.rb +201 -0
  6. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/collection.rb +11 -0
  7. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/model.rb +11 -0
  8. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/repository.rb +7 -0
  9. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/support/symbol.rb +21 -0
  10. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/version.rb +7 -0
  11. data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates.rb +15 -0
  12. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/abstract_adapter.rb +209 -0
  13. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/data_objects_adapter.rb +709 -0
  14. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/in_memory_adapter.rb +87 -0
  15. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/mysql_adapter.rb +136 -0
  16. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/postgres_adapter.rb +188 -0
  17. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
  18. data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters.rb +22 -0
  19. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/many_to_many.rb +147 -0
  20. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/many_to_one.rb +107 -0
  21. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/one_to_many.rb +318 -0
  22. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/one_to_one.rb +61 -0
  23. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/relationship.rb +223 -0
  24. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/relationship_chain.rb +81 -0
  25. data/lib/gems/dm-core-0.9.7/lib/dm-core/associations.rb +200 -0
  26. data/lib/gems/dm-core-0.9.7/lib/dm-core/auto_migrations.rb +105 -0
  27. data/lib/gems/dm-core-0.9.7/lib/dm-core/collection.rb +642 -0
  28. data/lib/gems/dm-core-0.9.7/lib/dm-core/dependency_queue.rb +32 -0
  29. data/lib/gems/dm-core-0.9.7/lib/dm-core/hook.rb +11 -0
  30. data/lib/gems/dm-core-0.9.7/lib/dm-core/identity_map.rb +42 -0
  31. data/lib/gems/dm-core-0.9.7/lib/dm-core/is.rb +16 -0
  32. data/lib/gems/dm-core-0.9.7/lib/dm-core/logger.rb +232 -0
  33. data/lib/gems/dm-core-0.9.7/lib/dm-core/migrations/destructive_migrations.rb +17 -0
  34. data/lib/gems/dm-core-0.9.7/lib/dm-core/migrator.rb +29 -0
  35. data/lib/gems/dm-core-0.9.7/lib/dm-core/model.rb +488 -0
  36. data/lib/gems/dm-core-0.9.7/lib/dm-core/naming_conventions.rb +84 -0
  37. data/lib/gems/dm-core-0.9.7/lib/dm-core/property.rb +663 -0
  38. data/lib/gems/dm-core-0.9.7/lib/dm-core/property_set.rb +169 -0
  39. data/lib/gems/dm-core-0.9.7/lib/dm-core/query.rb +628 -0
  40. data/lib/gems/dm-core-0.9.7/lib/dm-core/repository.rb +159 -0
  41. data/lib/gems/dm-core-0.9.7/lib/dm-core/resource.rb +637 -0
  42. data/lib/gems/dm-core-0.9.7/lib/dm-core/scope.rb +58 -0
  43. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/array.rb +13 -0
  44. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/assertions.rb +8 -0
  45. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/errors.rb +23 -0
  46. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/kernel.rb +11 -0
  47. data/lib/gems/dm-core-0.9.7/lib/dm-core/support/symbol.rb +41 -0
  48. data/lib/gems/dm-core-0.9.7/lib/dm-core/support.rb +7 -0
  49. data/lib/gems/dm-core-0.9.7/lib/dm-core/transaction.rb +267 -0
  50. data/lib/gems/dm-core-0.9.7/lib/dm-core/type.rb +160 -0
  51. data/lib/gems/dm-core-0.9.7/lib/dm-core/type_map.rb +80 -0
  52. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/boolean.rb +7 -0
  53. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/discriminator.rb +34 -0
  54. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/object.rb +24 -0
  55. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/paranoid_boolean.rb +34 -0
  56. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/paranoid_datetime.rb +33 -0
  57. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/serial.rb +9 -0
  58. data/lib/gems/dm-core-0.9.7/lib/dm-core/types/text.rb +10 -0
  59. data/lib/gems/dm-core-0.9.7/lib/dm-core/types.rb +19 -0
  60. data/lib/gems/dm-core-0.9.7/lib/dm-core/version.rb +3 -0
  61. data/lib/gems/dm-core-0.9.7/lib/dm-core.rb +217 -0
  62. data/lib/gems/dm-core-0.9.7/script/all +5 -0
  63. data/lib/gems/dm-core-0.9.7/script/performance.rb +284 -0
  64. data/lib/gems/dm-core-0.9.7/script/profile.rb +87 -0
  65. data/lib/gems/dm-migrations-0.9.7/lib/dm-migrations/version.rb +5 -0
  66. data/lib/gems/dm-migrations-0.9.7/lib/dm-migrations.rb +1 -0
  67. data/lib/gems/dm-migrations-0.9.7/lib/migration.rb +215 -0
  68. data/lib/gems/dm-migrations-0.9.7/lib/migration_runner.rb +88 -0
  69. data/lib/gems/dm-migrations-0.9.7/lib/spec/example/migration_example_group.rb +73 -0
  70. data/lib/gems/dm-migrations-0.9.7/lib/spec/matchers/migration_matchers.rb +107 -0
  71. data/lib/gems/dm-migrations-0.9.7/lib/sql/column.rb +9 -0
  72. data/lib/gems/dm-migrations-0.9.7/lib/sql/mysql.rb +52 -0
  73. data/lib/gems/dm-migrations-0.9.7/lib/sql/postgresql.rb +78 -0
  74. data/lib/gems/dm-migrations-0.9.7/lib/sql/sqlite3.rb +43 -0
  75. data/lib/gems/dm-migrations-0.9.7/lib/sql/table.rb +19 -0
  76. data/lib/gems/dm-migrations-0.9.7/lib/sql/table_creator.rb +81 -0
  77. data/lib/gems/dm-migrations-0.9.7/lib/sql/table_modifier.rb +53 -0
  78. data/lib/gems/dm-migrations-0.9.7/lib/sql.rb +10 -0
  79. data/lib/gems/dm-observer-0.9.7/lib/dm-observer/version.rb +5 -0
  80. data/lib/gems/dm-observer-0.9.7/lib/dm-observer.rb +91 -0
  81. data/lib/gems/dm-serializer-0.9.7/lib/dm-serializer/version.rb +5 -0
  82. data/lib/gems/dm-serializer-0.9.7/lib/dm-serializer.rb +183 -0
  83. data/lib/gems/dm-timestamps-0.9.7/lib/dm-timestamps/version.rb +5 -0
  84. data/lib/gems/dm-timestamps-0.9.7/lib/dm-timestamps.rb +57 -0
  85. data/lib/gems/dm-types-0.9.7/lib/dm-types/bcrypt_hash.rb +31 -0
  86. data/lib/gems/dm-types-0.9.7/lib/dm-types/csv.rb +28 -0
  87. data/lib/gems/dm-types-0.9.7/lib/dm-types/enum.rb +70 -0
  88. data/lib/gems/dm-types-0.9.7/lib/dm-types/epoch_time.rb +27 -0
  89. data/lib/gems/dm-types-0.9.7/lib/dm-types/file_path.rb +27 -0
  90. data/lib/gems/dm-types-0.9.7/lib/dm-types/flag.rb +61 -0
  91. data/lib/gems/dm-types-0.9.7/lib/dm-types/ip_address.rb +30 -0
  92. data/lib/gems/dm-types-0.9.7/lib/dm-types/json.rb +40 -0
  93. data/lib/gems/dm-types-0.9.7/lib/dm-types/regexp.rb +20 -0
  94. data/lib/gems/dm-types-0.9.7/lib/dm-types/serial.rb +8 -0
  95. data/lib/gems/dm-types-0.9.7/lib/dm-types/slug.rb +37 -0
  96. data/lib/gems/dm-types-0.9.7/lib/dm-types/uri.rb +29 -0
  97. data/lib/gems/dm-types-0.9.7/lib/dm-types/uuid.rb +64 -0
  98. data/lib/gems/dm-types-0.9.7/lib/dm-types/version.rb +5 -0
  99. data/lib/gems/dm-types-0.9.7/lib/dm-types/yaml.rb +36 -0
  100. data/lib/gems/dm-types-0.9.7/lib/dm-types.rb +28 -0
  101. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/absent_field_validator.rb +60 -0
  102. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/acceptance_validator.rb +76 -0
  103. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/auto_validate.rb +153 -0
  104. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/block_validator.rb +60 -0
  105. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/confirmation_validator.rb +80 -0
  106. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/contextual_validators.rb +56 -0
  107. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/custom_validator.rb +72 -0
  108. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/format_validator.rb +97 -0
  109. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/formats/email.rb +40 -0
  110. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/formats/url.rb +20 -0
  111. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/generic_validator.rb +100 -0
  112. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/length_validator.rb +113 -0
  113. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/method_validator.rb +68 -0
  114. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/numeric_validator.rb +83 -0
  115. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/primitive_validator.rb +60 -0
  116. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/required_field_validator.rb +88 -0
  117. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/support/object.rb +5 -0
  118. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/uniqueness_validator.rb +64 -0
  119. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/validation_errors.rb +63 -0
  120. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/version.rb +5 -0
  121. data/lib/gems/dm-validations-0.9.7/lib/dm-validations/within_validator.rb +53 -0
  122. data/lib/gems/dm-validations-0.9.7/lib/dm-validations.rb +234 -0
  123. data/lib/gems/json_pure-1.1.3/GPL +340 -0
  124. data/lib/gems/json_pure-1.1.3/VERSION +1 -0
  125. data/lib/gems/json_pure-1.1.3/bin/edit_json.rb +10 -0
  126. data/lib/gems/json_pure-1.1.3/bin/prettify_json.rb +76 -0
  127. data/lib/gems/json_pure-1.1.3/lib/json/Array.xpm +21 -0
  128. data/lib/gems/json_pure-1.1.3/lib/json/FalseClass.xpm +21 -0
  129. data/lib/gems/json_pure-1.1.3/lib/json/Hash.xpm +21 -0
  130. data/lib/gems/json_pure-1.1.3/lib/json/Key.xpm +73 -0
  131. data/lib/gems/json_pure-1.1.3/lib/json/NilClass.xpm +21 -0
  132. data/lib/gems/json_pure-1.1.3/lib/json/Numeric.xpm +28 -0
  133. data/lib/gems/json_pure-1.1.3/lib/json/String.xpm +96 -0
  134. data/lib/gems/json_pure-1.1.3/lib/json/TrueClass.xpm +21 -0
  135. data/lib/gems/json_pure-1.1.3/lib/json/add/core.rb +135 -0
  136. data/lib/gems/json_pure-1.1.3/lib/json/add/rails.rb +58 -0
  137. data/lib/gems/json_pure-1.1.3/lib/json/common.rb +354 -0
  138. data/lib/gems/json_pure-1.1.3/lib/json/editor.rb +1362 -0
  139. data/lib/gems/json_pure-1.1.3/lib/json/ext.rb +13 -0
  140. data/lib/gems/json_pure-1.1.3/lib/json/json.xpm +1499 -0
  141. data/lib/gems/json_pure-1.1.3/lib/json/pure/generator.rb +394 -0
  142. data/lib/gems/json_pure-1.1.3/lib/json/pure/parser.rb +259 -0
  143. data/lib/gems/json_pure-1.1.3/lib/json/pure.rb +75 -0
  144. data/lib/gems/json_pure-1.1.3/lib/json/version.rb +9 -0
  145. data/lib/gems/json_pure-1.1.3/lib/json.rb +235 -0
  146. data/lib/gems/launchy-0.3.2/bin/launchy +12 -0
  147. data/lib/gems/launchy-0.3.2/lib/launchy/application.rb +163 -0
  148. data/lib/gems/launchy-0.3.2/lib/launchy/browser.rb +85 -0
  149. data/lib/gems/launchy-0.3.2/lib/launchy/command_line.rb +48 -0
  150. data/lib/gems/launchy-0.3.2/lib/launchy/gemspec.rb +53 -0
  151. data/lib/gems/launchy-0.3.2/lib/launchy/specification.rb +133 -0
  152. data/lib/gems/launchy-0.3.2/lib/launchy/version.rb +18 -0
  153. data/lib/gems/launchy-0.3.2/lib/launchy.rb +58 -0
  154. data/lib/gems/uuidtools-1.0.3/lib/uuidtools/version.rb +32 -0
  155. data/lib/gems/uuidtools-1.0.3/lib/uuidtools.rb +648 -0
  156. data/lib/gems.rb +13 -0
  157. data/lib/mack-data_mapper/migration_generator/migration_generator.rb +5 -0
  158. data/lib/mack-data_mapper/migration_generator/templates/db/migrations/%=@migration_name%.rb.template +1 -1
  159. data/lib/mack-data_mapper/model_generator/manifest.yml +3 -3
  160. data/lib/mack-data_mapper/model_generator/model_generator.rb +8 -1
  161. data/lib/mack-data_mapper/model_generator/templates/model.rb.template +1 -1
  162. data/lib/mack-data_mapper/model_generator/templates/rspec.rb.template +1 -1
  163. data/lib/mack-data_mapper/model_generator/templates/test_case.rb.template +1 -1
  164. data/lib/mack-data_mapper.rb +3 -2
  165. data/lib/mack-data_mapper_tasks.rb +7 -0
  166. metadata +235 -86
@@ -0,0 +1,87 @@
1
+ module DataMapper
2
+ module Adapters
3
+ class InMemoryAdapter < AbstractAdapter
4
+ def initialize(name, uri_or_options)
5
+ @records = Hash.new { |hash,model| hash[model] = Array.new }
6
+ end
7
+
8
+ def create(resources)
9
+ resources.each do |resource|
10
+ @records[resource.model] << resource
11
+ end.size # just return the number of records
12
+ end
13
+
14
+ def update(attributes, query)
15
+ read_many(query).each do |resource|
16
+ attributes.each do |property,value|
17
+ property.set!(resource, value)
18
+ end
19
+ end.size
20
+ end
21
+
22
+ def read_one(query)
23
+ read(query, query.model, false)
24
+ end
25
+
26
+ def read_many(query)
27
+ Collection.new(query) do |set|
28
+ read(query, set, true)
29
+ end
30
+ end
31
+
32
+ def delete(query)
33
+ records = @records[query.model]
34
+
35
+ read_many(query).each do |resource|
36
+ records.delete(resource)
37
+ end.size
38
+ end
39
+
40
+ private
41
+
42
+ def read(query, set, many = true)
43
+ model = query.model
44
+ conditions = query.conditions
45
+
46
+ match_with = many ? :select : :detect
47
+
48
+ # Iterate over the records for this model, and return
49
+ # the ones that match the conditions
50
+ result = @records[model].send(match_with) do |resource|
51
+ conditions.all? do |tuple|
52
+ operator, property, bind_value = *tuple
53
+
54
+ value = property.get!(resource)
55
+
56
+ case operator
57
+ when :eql, :in then equality_comparison(bind_value, value)
58
+ when :not then !equality_comparison(bind_value, value)
59
+ when :like then Regexp.new(bind_value) =~ value
60
+ when :gt then !value.nil? && value > bind_value
61
+ when :gte then !value.nil? && value >= bind_value
62
+ when :lt then !value.nil? && value < bind_value
63
+ when :lte then !value.nil? && value <= bind_value
64
+ else raise "Invalid query operator: #{operator.inspect}"
65
+ end
66
+ end
67
+ end
68
+
69
+ return result unless many
70
+
71
+ # TODO Sort
72
+
73
+ # TODO Limit
74
+
75
+ set.replace(result)
76
+ end
77
+
78
+ def equality_comparison(bind_value, value)
79
+ case bind_value
80
+ when Array, Range then bind_value.include?(value)
81
+ when NilClass then value.nil?
82
+ else bind_value == value
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,136 @@
1
+ gem 'do_mysql', '~>0.9.7'
2
+ require 'do_mysql'
3
+
4
+ module DataMapper
5
+ module Adapters
6
+ # Options:
7
+ # host, user, password, database (path), socket(uri query string), port
8
+ class MysqlAdapter < DataObjectsAdapter
9
+ module SQL
10
+ private
11
+
12
+ def supports_default_values?
13
+ false
14
+ end
15
+
16
+ def quote_table_name(table_name)
17
+ "`#{table_name.gsub('`', '``')}`"
18
+ end
19
+
20
+ def quote_column_name(column_name)
21
+ "`#{column_name.gsub('`', '``')}`"
22
+ end
23
+
24
+ def quote_column_value(column_value)
25
+ case column_value
26
+ when TrueClass then quote_column_value(1)
27
+ when FalseClass then quote_column_value(0)
28
+ else
29
+ super
30
+ end
31
+ end
32
+ end #module SQL
33
+
34
+ include SQL
35
+
36
+ # TODO: move to dm-more/dm-migrations
37
+ module Migration
38
+ # TODO: move to dm-more/dm-migrations (if possible)
39
+ def storage_exists?(storage_name)
40
+ statement = <<-EOS.compress_lines
41
+ SELECT COUNT(*)
42
+ FROM `information_schema`.`tables`
43
+ WHERE `table_type` = 'BASE TABLE'
44
+ AND `table_schema` = ?
45
+ AND `table_name` = ?
46
+ EOS
47
+
48
+ query(statement, db_name, storage_name).first > 0
49
+ end
50
+
51
+ # TODO: move to dm-more/dm-migrations (if possible)
52
+ def field_exists?(storage_name, field_name)
53
+ statement = <<-EOS.compress_lines
54
+ SELECT COUNT(*)
55
+ FROM `information_schema`.`columns`
56
+ WHERE `table_schema` = ?
57
+ AND `table_name` = ?
58
+ AND `column_name` = ?
59
+ EOS
60
+
61
+ query(statement, db_name, storage_name, field_name).first > 0
62
+ end
63
+
64
+ private
65
+
66
+ # TODO: move to dm-more/dm-migrations (if possible)
67
+ def db_name
68
+ @uri.path.split('/').last
69
+ end
70
+
71
+ module SQL
72
+ private
73
+
74
+ # TODO: move to dm-more/dm-migrations
75
+ def supports_serial?
76
+ true
77
+ end
78
+
79
+ # TODO: move to dm-more/dm-migrations
80
+ def create_table_statement(repository, model)
81
+ "#{super} ENGINE = InnoDB CHARACTER SET #{character_set} COLLATE #{collation}"
82
+ end
83
+
84
+ # TODO: move to dm-more/dm-migrations
85
+ def property_schema_hash(property, model)
86
+ schema = super
87
+ schema.delete(:default) if schema[:primitive] == 'TEXT'
88
+ schema
89
+ end
90
+
91
+ # TODO: move to dm-more/dm-migrations
92
+ def property_schema_statement(schema)
93
+ statement = super
94
+ statement << ' AUTO_INCREMENT' if supports_serial? && schema[:serial?]
95
+ statement
96
+ end
97
+
98
+ # TODO: move to dm-more/dm-migrations
99
+ def character_set
100
+ @character_set ||= show_variable('character_set_connection') || 'utf8'
101
+ end
102
+
103
+ # TODO: move to dm-more/dm-migrations
104
+ def collation
105
+ @collation ||= show_variable('collation_connection') || 'utf8_general_ci'
106
+ end
107
+
108
+ # TODO: move to dm-more/dm-migrations
109
+ def show_variable(name)
110
+ query('SHOW VARIABLES WHERE `variable_name` = ?', name).first.value rescue nil
111
+ end
112
+ end # module SQL
113
+
114
+ include SQL
115
+
116
+ module ClassMethods
117
+ # TypeMap for MySql databases.
118
+ #
119
+ # @return <DataMapper::TypeMap> default TypeMap for MySql databases.
120
+ #
121
+ # TODO: move to dm-more/dm-migrations
122
+ def type_map
123
+ @type_map ||= TypeMap.new(super) do |tm|
124
+ tm.map(Integer).to('INT').with(:size => 11)
125
+ tm.map(TrueClass).to('TINYINT').with(:size => 1) # TODO: map this to a BIT or CHAR(0) field?
126
+ tm.map(Object).to('TEXT')
127
+ end
128
+ end
129
+ end # module ClassMethods
130
+ end # module Migration
131
+
132
+ include Migration
133
+ extend Migration::ClassMethods
134
+ end # class MysqlAdapter
135
+ end # module Adapters
136
+ end # module DataMapper
@@ -0,0 +1,188 @@
1
+ gem 'do_postgres', '~>0.9.7'
2
+ require 'do_postgres'
3
+
4
+ module DataMapper
5
+ module Adapters
6
+ class PostgresAdapter < DataObjectsAdapter
7
+ module SQL
8
+ private
9
+
10
+ def supports_returning?
11
+ true
12
+ end
13
+ end #module SQL
14
+
15
+ 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 = <<-EOS.compress_lines
22
+ SELECT COUNT(*)
23
+ FROM "information_schema"."columns"
24
+ WHERE "table_name" = ?
25
+ AND "table_schema" = current_schema()
26
+ EOS
27
+
28
+ query(statement, storage_name).first > 0
29
+ end
30
+
31
+ # TODO: move to dm-more/dm-migrations (if possible)
32
+ def field_exists?(storage_name, column_name)
33
+ statement = <<-EOS.compress_lines
34
+ SELECT COUNT(*)
35
+ FROM "pg_class"
36
+ JOIN "pg_attribute" ON "pg_class"."oid" = "pg_attribute"."attrelid"
37
+ WHERE "pg_attribute"."attname" = ?
38
+ AND "pg_class"."relname" = ?
39
+ AND "pg_attribute"."attnum" >= 0
40
+ EOS
41
+
42
+ query(statement, column_name, storage_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 "pg_class"
116
+ WHERE "relkind" = 'S' AND "relname" = ?
117
+ EOS
118
+
119
+ query(statement, sequence_name(repository, property)).first > 0
120
+ end
121
+
122
+ # TODO: move to dm-more/dm-migrations
123
+ def create_sequence_statement(repository, property)
124
+ "CREATE SEQUENCE #{quote_column_name(sequence_name(repository, property))}"
125
+ end
126
+
127
+ # TODO: move to dm-more/dm-migrations
128
+ def drop_sequence_statement(repository, property)
129
+ "DROP SEQUENCE IF EXISTS #{quote_column_name(sequence_name(repository, property))}"
130
+ end
131
+
132
+ # TODO: move to dm-more/dm-migrations
133
+ def property_schema_statement(schema)
134
+ statement = super
135
+
136
+ if schema.has_key?(:sequence_name)
137
+ statement << " DEFAULT nextval('#{schema[:sequence_name]}') NOT NULL"
138
+ end
139
+
140
+ statement
141
+ end
142
+
143
+ # TODO: move to dm-more/dm-migrations
144
+ def property_schema_hash(repository, property)
145
+ schema = super
146
+
147
+ if property.serial?
148
+ schema.delete(:default) # the sequence will be the default
149
+ schema[:sequence_name] = sequence_name(repository, property)
150
+ end
151
+
152
+ # TODO: see if TypeMap can be updated to set specific attributes to nil
153
+ # for different adapters. precision/scale are perfect examples for
154
+ # Postgres floats
155
+
156
+ # Postgres does not support precision and scale for Float
157
+ if property.primitive == Float
158
+ schema.delete(:precision)
159
+ schema.delete(:scale)
160
+ end
161
+
162
+ schema
163
+ end
164
+ end # module SQL
165
+
166
+ include SQL
167
+
168
+ module ClassMethods
169
+ # TypeMap for PostgreSQL databases.
170
+ #
171
+ # @return <DataMapper::TypeMap> default TypeMap for PostgreSQL databases.
172
+ #
173
+ # TODO: move to dm-more/dm-migrations
174
+ def type_map
175
+ @type_map ||= TypeMap.new(super) do |tm|
176
+ tm.map(DateTime).to('TIMESTAMP')
177
+ tm.map(Integer).to('INT4')
178
+ tm.map(Float).to('FLOAT8')
179
+ end
180
+ end
181
+ end # module ClassMethods
182
+ end # module Migration
183
+
184
+ include Migration
185
+ extend Migration::ClassMethods
186
+ end # class PostgresAdapter
187
+ end # module Adapters
188
+ end # module DataMapper
@@ -0,0 +1,105 @@
1
+ gem 'do_sqlite3', '~>0.9.7'
2
+ require 'do_sqlite3'
3
+
4
+ module DataMapper
5
+ module Adapters
6
+ 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
+ end # class Sqlite3Adapter
104
+ end # module Adapters
105
+ end # module DataMapper
@@ -0,0 +1,22 @@
1
+ dir = Pathname(__FILE__).dirname.expand_path / 'adapters'
2
+
3
+ require dir / 'abstract_adapter'
4
+ require dir / 'in_memory_adapter'
5
+
6
+ # TODO Factor these out into dm-more
7
+ require dir / 'data_objects_adapter'
8
+ begin
9
+ require dir / 'sqlite3_adapter'
10
+ rescue LoadError
11
+ # ignore it
12
+ end
13
+ begin
14
+ require dir / 'mysql_adapter'
15
+ rescue LoadError
16
+ # ignore it
17
+ end
18
+ begin
19
+ require dir / 'postgres_adapter'
20
+ rescue LoadError
21
+ # ignore it
22
+ end
@@ -0,0 +1,147 @@
1
+ require File.join(File.dirname(__FILE__), "one_to_many")
2
+ module DataMapper
3
+ module Associations
4
+ module ManyToMany
5
+ extend Assertions
6
+
7
+ # Setup many to many relationship between two models
8
+ # -
9
+ # @api private
10
+ def self.setup(name, model, options = {})
11
+ assert_kind_of 'name', name, Symbol
12
+ assert_kind_of 'model', model, Model
13
+ assert_kind_of 'options', options, Hash
14
+
15
+ repository_name = model.repository.name
16
+
17
+ model.class_eval <<-EOS, __FILE__, __LINE__
18
+ def #{name}(query = {})
19
+ #{name}_association.all(query)
20
+ end
21
+
22
+ def #{name}=(children)
23
+ #{name}_association.replace(children)
24
+ end
25
+
26
+ private
27
+
28
+ def #{name}_association
29
+ @#{name}_association ||= begin
30
+ unless relationship = model.relationships(#{repository_name.inspect})[#{name.inspect}]
31
+ raise ArgumentError, "Relationship #{name.inspect} does not exist in \#{model}"
32
+ end
33
+ association = Proxy.new(relationship, self)
34
+ parent_associations << association
35
+ association
36
+ end
37
+ end
38
+ EOS
39
+
40
+ opts = options.dup
41
+ opts.delete(:through)
42
+ opts[:child_model] ||= opts.delete(:class_name) || Extlib::Inflection.classify(name)
43
+ opts[:parent_model] = model
44
+ opts[:repository_name] = repository_name
45
+ opts[:remote_relationship_name] ||= opts.delete(:remote_name) || Extlib::Inflection.tableize(opts[:child_model])
46
+ opts[:parent_key] = opts[:parent_key]
47
+ opts[:child_key] = opts[:child_key]
48
+ opts[:mutable] = true
49
+
50
+ names = [ opts[:child_model], opts[:parent_model].name ].sort
51
+ model_name = names.join.gsub("::", "")
52
+ storage_name = Extlib::Inflection.tableize(Extlib::Inflection.pluralize(names[0]) + names[1])
53
+
54
+ opts[:near_relationship_name] = Extlib::Inflection.tableize(model_name).to_sym
55
+
56
+ model.has(model.n, opts[:near_relationship_name])
57
+
58
+ relationship = model.relationships(repository_name)[name] = RelationshipChain.new(opts)
59
+
60
+ unless Object.const_defined?(model_name)
61
+ model = DataMapper::Model.new(storage_name)
62
+
63
+ model.class_eval <<-EOS, __FILE__, __LINE__
64
+ def self.name; #{model_name.inspect} end
65
+ def self.default_repository_name; #{repository_name.inspect} end
66
+ def self.many_to_many; true end
67
+ EOS
68
+
69
+ names.each do |n|
70
+ model.belongs_to(Extlib::Inflection.underscore(n).gsub("/", "_").to_sym, :class_name => n)
71
+ end
72
+
73
+ Object.const_set(model_name, model)
74
+ end
75
+
76
+ relationship
77
+ end
78
+
79
+ class Proxy < DataMapper::Associations::OneToMany::Proxy
80
+ def delete(resource)
81
+ through = near_association.get(*(@parent.key + resource.key))
82
+ near_association.delete(through)
83
+ orphan_resource(super)
84
+ end
85
+
86
+ def clear
87
+ near_association.clear
88
+ super
89
+ end
90
+
91
+ def destroy
92
+ near_association.destroy
93
+ super
94
+ end
95
+
96
+ def save
97
+ end
98
+
99
+ private
100
+
101
+ def new_child(attributes)
102
+ remote_relationship.parent_model.new(attributes)
103
+ end
104
+
105
+ def relate_resource(resource)
106
+ assert_mutable
107
+ add_default_association_values(resource)
108
+ @orphans.delete(resource)
109
+
110
+ # TODO: fix this so it does not automatically save on append, if possible
111
+ resource.save if resource.new_record?
112
+ through_resource = @relationship.child_model.new
113
+ @relationship.child_key.zip(@relationship.parent_key) do |child_key,parent_key|
114
+ through_resource.send("#{child_key.name}=", parent_key.get(@parent))
115
+ end
116
+ remote_relationship.child_key.zip(remote_relationship.parent_key) do |child_key,parent_key|
117
+ through_resource.send("#{child_key.name}=", parent_key.get(resource))
118
+ end
119
+ near_association << through_resource
120
+
121
+ resource
122
+ end
123
+
124
+ def orphan_resource(resource)
125
+ assert_mutable
126
+ @orphans << resource
127
+ resource
128
+ end
129
+
130
+ def assert_mutable
131
+ end
132
+
133
+ def remote_relationship
134
+ @remote_relationship ||= @relationship.send(:remote_relationship)
135
+ end
136
+
137
+ def near_association
138
+ @near_association ||= @parent.send(near_relationship_name)
139
+ end
140
+
141
+ def near_relationship_name
142
+ @near_relationship_name ||= @relationship.send(:instance_variable_get, :@near_relationship_name)
143
+ end
144
+ end # class Proxy
145
+ end # module ManyToMany
146
+ end # module Associations
147
+ end # module DataMapper