datamapper 0.3.2 → 0.9.3

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 (180) hide show
  1. data/History.txt +0 -0
  2. data/Manifest.txt +5 -0
  3. data/README.txt +11 -0
  4. data/Rakefile +70 -0
  5. data/lib/datamapper.rb +8 -0
  6. metadata +152 -319
  7. data/CHANGELOG +0 -145
  8. data/FAQ +0 -96
  9. data/MIT-LICENSE +0 -22
  10. data/QUICKLINKS +0 -12
  11. data/README +0 -105
  12. data/environment.rb +0 -62
  13. data/example.rb +0 -156
  14. data/lib/data_mapper.rb +0 -88
  15. data/lib/data_mapper/adapters/abstract_adapter.rb +0 -43
  16. data/lib/data_mapper/adapters/data_object_adapter.rb +0 -480
  17. data/lib/data_mapper/adapters/mysql_adapter.rb +0 -72
  18. data/lib/data_mapper/adapters/postgresql_adapter.rb +0 -258
  19. data/lib/data_mapper/adapters/sql/coersion.rb +0 -134
  20. data/lib/data_mapper/adapters/sql/commands/load_command.rb +0 -545
  21. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +0 -34
  22. data/lib/data_mapper/adapters/sql/mappings/column.rb +0 -279
  23. data/lib/data_mapper/adapters/sql/mappings/conditions.rb +0 -172
  24. data/lib/data_mapper/adapters/sql/mappings/schema.rb +0 -60
  25. data/lib/data_mapper/adapters/sql/mappings/table.rb +0 -459
  26. data/lib/data_mapper/adapters/sql/quoting.rb +0 -24
  27. data/lib/data_mapper/adapters/sqlite3_adapter.rb +0 -159
  28. data/lib/data_mapper/associations.rb +0 -106
  29. data/lib/data_mapper/associations/belongs_to_association.rb +0 -160
  30. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +0 -437
  31. data/lib/data_mapper/associations/has_many_association.rb +0 -283
  32. data/lib/data_mapper/associations/has_n_association.rb +0 -143
  33. data/lib/data_mapper/associations/reference.rb +0 -47
  34. data/lib/data_mapper/attributes.rb +0 -73
  35. data/lib/data_mapper/auto_migrations.rb +0 -36
  36. data/lib/data_mapper/base.rb +0 -17
  37. data/lib/data_mapper/callbacks.rb +0 -107
  38. data/lib/data_mapper/context.rb +0 -112
  39. data/lib/data_mapper/database.rb +0 -234
  40. data/lib/data_mapper/dependency_queue.rb +0 -28
  41. data/lib/data_mapper/embedded_value.rb +0 -145
  42. data/lib/data_mapper/identity_map.rb +0 -47
  43. data/lib/data_mapper/is/tree.rb +0 -121
  44. data/lib/data_mapper/migration.rb +0 -155
  45. data/lib/data_mapper/persistence.rb +0 -852
  46. data/lib/data_mapper/property.rb +0 -310
  47. data/lib/data_mapper/query.rb +0 -164
  48. data/lib/data_mapper/support/blank.rb +0 -35
  49. data/lib/data_mapper/support/connection_pool.rb +0 -117
  50. data/lib/data_mapper/support/enumerable.rb +0 -35
  51. data/lib/data_mapper/support/errors.rb +0 -16
  52. data/lib/data_mapper/support/inflector.rb +0 -265
  53. data/lib/data_mapper/support/object.rb +0 -54
  54. data/lib/data_mapper/support/serialization.rb +0 -96
  55. data/lib/data_mapper/support/silence.rb +0 -10
  56. data/lib/data_mapper/support/string.rb +0 -72
  57. data/lib/data_mapper/support/struct.rb +0 -7
  58. data/lib/data_mapper/support/symbol.rb +0 -82
  59. data/lib/data_mapper/support/typed_set.rb +0 -65
  60. data/lib/data_mapper/types/base.rb +0 -44
  61. data/lib/data_mapper/types/string.rb +0 -34
  62. data/lib/data_mapper/validatable_extensions/errors.rb +0 -12
  63. data/lib/data_mapper/validatable_extensions/macros.rb +0 -7
  64. data/lib/data_mapper/validatable_extensions/validatable_instance_methods.rb +0 -62
  65. data/lib/data_mapper/validatable_extensions/validation_base.rb +0 -18
  66. data/lib/data_mapper/validatable_extensions/validations/formats/email.rb +0 -43
  67. data/lib/data_mapper/validatable_extensions/validations/validates_acceptance_of.rb +0 -7
  68. data/lib/data_mapper/validatable_extensions/validations/validates_confirmation_of.rb +0 -7
  69. data/lib/data_mapper/validatable_extensions/validations/validates_each.rb +0 -7
  70. data/lib/data_mapper/validatable_extensions/validations/validates_format_of.rb +0 -28
  71. data/lib/data_mapper/validatable_extensions/validations/validates_length_of.rb +0 -15
  72. data/lib/data_mapper/validatable_extensions/validations/validates_numericality_of.rb +0 -7
  73. data/lib/data_mapper/validatable_extensions/validations/validates_presence_of.rb +0 -7
  74. data/lib/data_mapper/validatable_extensions/validations/validates_true_for.rb +0 -7
  75. data/lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb +0 -40
  76. data/lib/data_mapper/validations.rb +0 -20
  77. data/lib/data_mapper/validations/number_validator.rb +0 -40
  78. data/lib/data_mapper/validations/string_validator.rb +0 -20
  79. data/lib/data_mapper/validations/validator.rb +0 -13
  80. data/performance.rb +0 -307
  81. data/plugins/can_has_sphinx/LICENSE +0 -23
  82. data/plugins/can_has_sphinx/README +0 -4
  83. data/plugins/can_has_sphinx/REVISION +0 -1
  84. data/plugins/can_has_sphinx/Rakefile +0 -22
  85. data/plugins/can_has_sphinx/init.rb +0 -1
  86. data/plugins/can_has_sphinx/install.rb +0 -1
  87. data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +0 -123
  88. data/plugins/can_has_sphinx/lib/sphinx.rb +0 -460
  89. data/plugins/can_has_sphinx/scripts/sphinx.sh +0 -47
  90. data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +0 -41
  91. data/profile_data_mapper.rb +0 -40
  92. data/rakefile.rb +0 -159
  93. data/spec/acts_as_tree_spec.rb +0 -67
  94. data/spec/adapters/data_object_adapter_spec.rb +0 -31
  95. data/spec/associations/belongs_to_association_spec.rb +0 -98
  96. data/spec/associations/has_and_belongs_to_many_association_spec.rb +0 -377
  97. data/spec/associations/has_many_association_spec.rb +0 -337
  98. data/spec/attributes_spec.rb +0 -52
  99. data/spec/auto_migrations_spec.rb +0 -101
  100. data/spec/callbacks_spec.rb +0 -186
  101. data/spec/can_has_sphinx.rb +0 -5
  102. data/spec/coersion_spec.rb +0 -41
  103. data/spec/column_spec.rb +0 -114
  104. data/spec/count_command_spec.rb +0 -45
  105. data/spec/database_spec.rb +0 -18
  106. data/spec/dataobjects_spec.rb +0 -27
  107. data/spec/delete_command_spec.rb +0 -11
  108. data/spec/dependency_spec.rb +0 -29
  109. data/spec/embedded_value_spec.rb +0 -161
  110. data/spec/fixtures/animals.yaml +0 -33
  111. data/spec/fixtures/animals_exhibits.yaml +0 -2
  112. data/spec/fixtures/careers.yaml +0 -5
  113. data/spec/fixtures/comments.yaml +0 -1
  114. data/spec/fixtures/exhibits.yaml +0 -90
  115. data/spec/fixtures/fruit.yaml +0 -6
  116. data/spec/fixtures/people.yaml +0 -37
  117. data/spec/fixtures/posts.yaml +0 -3
  118. data/spec/fixtures/projects.yaml +0 -13
  119. data/spec/fixtures/sections.yaml +0 -5
  120. data/spec/fixtures/serializers.yaml +0 -6
  121. data/spec/fixtures/tasks.yaml +0 -6
  122. data/spec/fixtures/tasks_tasks.yaml +0 -2
  123. data/spec/fixtures/tomatoes.yaml +0 -1
  124. data/spec/fixtures/users.yaml +0 -1
  125. data/spec/fixtures/zoos.yaml +0 -24
  126. data/spec/is_a_tree_spec.rb +0 -149
  127. data/spec/legacy_spec.rb +0 -16
  128. data/spec/load_command_spec.rb +0 -322
  129. data/spec/magic_columns_spec.rb +0 -26
  130. data/spec/migration_spec.rb +0 -267
  131. data/spec/mock_adapter.rb +0 -20
  132. data/spec/models/animal.rb +0 -12
  133. data/spec/models/candidate.rb +0 -8
  134. data/spec/models/career.rb +0 -7
  135. data/spec/models/chain.rb +0 -8
  136. data/spec/models/comment.rb +0 -6
  137. data/spec/models/exhibit.rb +0 -14
  138. data/spec/models/fence.rb +0 -7
  139. data/spec/models/fruit.rb +0 -8
  140. data/spec/models/job.rb +0 -8
  141. data/spec/models/person.rb +0 -30
  142. data/spec/models/post.rb +0 -14
  143. data/spec/models/project.rb +0 -41
  144. data/spec/models/sales_person.rb +0 -5
  145. data/spec/models/section.rb +0 -8
  146. data/spec/models/serializer.rb +0 -5
  147. data/spec/models/task.rb +0 -9
  148. data/spec/models/tomato.rb +0 -27
  149. data/spec/models/user.rb +0 -12
  150. data/spec/models/zoo.rb +0 -13
  151. data/spec/natural_key_spec.rb +0 -36
  152. data/spec/paranoia_spec.rb +0 -38
  153. data/spec/persistence_spec.rb +0 -479
  154. data/spec/postgres_spec.rb +0 -96
  155. data/spec/property_spec.rb +0 -151
  156. data/spec/query_spec.rb +0 -77
  157. data/spec/save_command_spec.rb +0 -94
  158. data/spec/schema_spec.rb +0 -8
  159. data/spec/serialize_spec.rb +0 -19
  160. data/spec/single_table_inheritance_spec.rb +0 -43
  161. data/spec/spec_helper.rb +0 -45
  162. data/spec/support/blank_spec.rb +0 -8
  163. data/spec/support/inflector_spec.rb +0 -41
  164. data/spec/support/object_spec.rb +0 -9
  165. data/spec/support/serialization_spec.rb +0 -61
  166. data/spec/support/silence_spec.rb +0 -15
  167. data/spec/support/string_spec.rb +0 -7
  168. data/spec/support/struct_spec.rb +0 -12
  169. data/spec/support/typed_set_spec.rb +0 -66
  170. data/spec/symbolic_operators_spec.rb +0 -27
  171. data/spec/table_spec.rb +0 -79
  172. data/spec/types/string.rb +0 -81
  173. data/spec/validates_confirmation_of_spec.rb +0 -55
  174. data/spec/validates_format_of_spec.rb +0 -78
  175. data/spec/validates_length_of_spec.rb +0 -117
  176. data/spec/validates_uniqueness_of_spec.rb +0 -92
  177. data/spec/validations/number_validator.rb +0 -59
  178. data/spec/validations/string_validator.rb +0 -14
  179. data/spec/validations_spec.rb +0 -141
  180. data/tasks/fixtures.rb +0 -53
data/example.rb DELETED
@@ -1,156 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- ENV['LOG_NAME'] ||= 'example'
4
- require 'environment'
5
-
6
- # Define a fixtures helper method to load up our test data.
7
- def fixtures(name)
8
- entry = YAML::load_file(File.dirname(__FILE__) + "/spec/fixtures/#{name}.yaml")
9
- klass = begin
10
- Kernel::const_get(Inflector.classify(Inflector.singularize(name)))
11
- rescue
12
- nil
13
- end
14
-
15
- unless klass.nil?
16
- database.logger.debug { "AUTOMIGRATE: #{klass}" }
17
- klass.auto_migrate!
18
-
19
- (entry.kind_of?(Array) ? entry : [entry]).each do |hash|
20
- if hash['type']
21
- Object::const_get(hash['type'])::create(hash)
22
- else
23
- klass::create(hash)
24
- end
25
- end
26
- else
27
- table = database.table(name.to_s)
28
- table.create! true
29
- table.activate_associations!
30
-
31
- #pp database.schema
32
-
33
- (entry.kind_of?(Array) ? entry : [entry]).each do |hash|
34
- table.insert(hash)
35
- end
36
- end
37
- end
38
-
39
-
40
- # Pre-fill the database so non-destructive tests don't need to reload fixtures.
41
- Dir[File.dirname(__FILE__) + "/spec/fixtures/*.yaml"].each do |path|
42
- fixtures(File::basename(path).sub(/\.yaml$/, ''))
43
- end
44
-
45
- require 'irb'
46
-
47
- # database { IRB::start }
48
- IRB::start
49
-
50
- if false
51
-
52
- # Simple example to setup a database:
53
- DataMapper::Database.setup({
54
- :adapter => 'mysql',
55
- :database => 'data_mapper_1',
56
- :username => 'root'
57
- })
58
-
59
- class Animal #:nodoc:
60
- include DataMapper::Persistence
61
-
62
- set_table_name 'animals' # Just as an example. Same inflector as Rails,
63
- # so this really isn't necessary.
64
-
65
- property :name, :string
66
- property :notes, :string, :lazy => true
67
-
68
- has_and_belongs_to_many :exhibits
69
- end
70
-
71
- class Exhibit #:nodoc:
72
- include DataMapper::Persistence
73
-
74
- property :name, :string
75
- belongs_to :zoo
76
- end
77
-
78
- class Zoo #:nodoc:
79
- include DataMapper::Persistence
80
-
81
- property :name, :string
82
- has_many :exhibits
83
- end
84
-
85
- class Person #:nodoc:
86
- include DataMapper::Persistence
87
-
88
- property :name, :string
89
- property :age, :integer
90
- property :occupation, :string
91
- property :notes, :text, :lazy => true
92
-
93
- # Generates Person::Address class:
94
- embed :address do
95
- property :street, :string
96
- property :city, :string
97
- property :state, :string, :size => 2
98
- property :postal_code, :string
99
- end
100
- end
101
-
102
- # Compatible with ActiveRecord finder syntax:
103
- Zoo.find(1)
104
- Zoo.find(:first, :conditions => ['name = ?', 'Galveston'])
105
- Zoo.find(:all)
106
-
107
- # These are options as well:
108
- Zoo[1]
109
- Zoo.first(:name => 'Galveston')
110
- Zoo.all
111
-
112
- # Or even this as an alias to ::first:
113
- Zoo[:name => 'Galveston']
114
-
115
- # EmbeddedValues are just nice sugar to partition
116
- # denormalized data.
117
- Person.first.address.city
118
-
119
- # Remove all data in a table...
120
- Person.truncate!
121
-
122
- # Create a new object...
123
- Person::create(:name => 'Sam', :age => 30, :occupation => 'Software Monkey')
124
-
125
- # Saving only updates the values that have changed,
126
- # and is skipped entirely if the object is not dirty.
127
- dumbo = Animal.first(:name => 'Elephant')
128
- dumbo.notes = 'He can fly!'
129
- dumbo.save # returns true
130
- dumbo.save # The object is no longer dirty, so returns false
131
-
132
- # DataMapper associations are loaded as sets.
133
- # Here's the code:
134
- Zoo.all.each { |zoo| zoo.exhibits.entries }
135
- # The important bit to understand about the above is that
136
- # every Zoo that was loaded by Zoo.all has a reference to
137
- # every other Zoo it was loaded with through Zoo#loaded_set.
138
- # This is then used to load all other instances in the set
139
- # when the association of one instance is accessed. So while
140
- # it looks like we'd run into the dreaded 1+N query problem
141
- # with the above, we actually avoid it entirely. The above
142
- # code will only execute two queries. The first to find all
143
- # zoos, the second to load all exhibits with zoo_id's that
144
- # are a part of the set of loaded zoos.
145
-
146
-
147
- # Objects within the same session are uniqued, so this is both
148
- # faster, and fulfills obvious expectations.
149
- database do
150
- Zoo.first == Zoo.first
151
- end
152
-
153
- # DataMapper find_by_sql equivilent
154
- database.query("SELECT * FROM zoos")
155
-
156
- end
@@ -1,88 +0,0 @@
1
- # This file begins the loading sequence.
2
- #
3
- # Quick Overview:
4
- # * Requires set, fastthread, support libs, and base
5
- # * Sets the applications root and environment for compatibility with rails or merb
6
- # * Checks for the database.yml and loads it if it exists
7
- # * Sets up the database using the config from the yaml file or from the environment
8
- # *
9
-
10
- # This line just let's us require anything in the +lib+ sub-folder
11
- # without specifying a full path.
12
- unless defined?(DM_PLUGINS_ROOT)
13
- $LOAD_PATH.unshift(File.dirname(__FILE__))
14
-
15
- DM_PLUGINS_ROOT = (File.dirname(__FILE__) + '/../plugins')
16
- end
17
-
18
- # Require the basics...
19
- require 'date'
20
- require 'time'
21
- require 'rubygems'
22
- require 'yaml'
23
- require 'set'
24
- require 'fastthread'
25
- require 'validatable'
26
- require 'data_mapper/support/object'
27
- require 'data_mapper/support/blank'
28
- require 'data_mapper/support/enumerable'
29
- require 'data_mapper/support/symbol'
30
- require 'data_mapper/support/string'
31
- require 'data_mapper/support/silence'
32
- require 'data_mapper/support/inflector'
33
- require 'data_mapper/support/errors'
34
- require 'data_mapper/support/typed_set'
35
- require 'data_mapper/database'
36
- require 'data_mapper/persistence'
37
- require 'data_mapper/base'
38
- require 'data_mapper/types/string'
39
-
40
-
41
- begin
42
- # This block of code is for compatibility with Ruby On Rails' or Merb's database.yml
43
- # file, allowing you to simply require the data_mapper.rb in your
44
- # Rails application's environment.rb to configure the DataMapper.
45
- unless defined?(DM_APP_ROOT)
46
- application_root, application_environment = *if defined?(RAILS_ROOT)
47
- [RAILS_ROOT, RAILS_ENV]
48
- end
49
-
50
- DM_APP_ROOT = application_root || Dir::pwd
51
-
52
- if application_root && File.exists?(application_root + '/config/database.yml')
53
-
54
- database_configurations = YAML::load_file(application_root + '/config/database.yml')
55
- current_database_config = database_configurations[application_environment] || database_configurations[application_environment.to_sym]
56
-
57
- config = lambda { |key| current_database_config[key.to_s] || current_database_config[key] }
58
-
59
- default_database_config = {
60
- :adapter => config[:adapter],
61
- :host => config[:host],
62
- :database => config[:database],
63
- :username => config[:username],
64
- :password => config[:password],
65
- :socket => config[:socket]
66
- }
67
-
68
- DataMapper::Database.setup(default_database_config)
69
-
70
- elsif application_root && FileTest.directory?(application_root + '/config')
71
-
72
- %w(development testing production).map do |environment|
73
- <<-EOS.margin
74
- #{environment}:
75
- adapter: mysql
76
- username: root
77
- password:
78
- host: localhost
79
- database: #{File.dirname(DM_APP_ROOT).split('/').last}_#{environment}
80
- EOS
81
- end
82
-
83
- #File::open(application_root + '/config/database.yml')
84
- end
85
- end
86
- rescue Exception
87
- warn "Could not connect to database specified by database.yml."
88
- end
@@ -1,43 +0,0 @@
1
- module DataMapper
2
- module Adapters
3
-
4
- class AbstractAdapter
5
-
6
- # Instantiate an Adapter by passing it a DataMapper::Database
7
- # object for configuration.
8
- def initialize(configuration)
9
- @configuration = configuration
10
- end
11
-
12
- def index_path
13
- @configuration.index_path
14
- end
15
-
16
- def name
17
- @configuration.name
18
- end
19
-
20
- def delete(instance_or_klass, options = nil)
21
- raise NotImplementedError.new
22
- end
23
-
24
- def save(database_context, instance)
25
- raise NotImplementedError.new
26
- end
27
-
28
- def load(database_context, klass, options)
29
- raise NotImplementedError.new
30
- end
31
-
32
- def get(database_context, klass, *keys)
33
- raise NotImplementedError.new
34
- end
35
-
36
- def logger
37
- @logger || @logger = @configuration.logger
38
- end
39
-
40
- end # class AbstractAdapter
41
-
42
- end # module Adapters
43
- end # module DataMapper
@@ -1,480 +0,0 @@
1
- require 'data_mapper/adapters/abstract_adapter'
2
- require 'data_mapper/adapters/sql/commands/load_command'
3
- require 'data_mapper/adapters/sql/coersion'
4
- require 'data_mapper/adapters/sql/quoting'
5
- require 'data_mapper/adapters/sql/mappings/schema'
6
- require 'data_mapper/support/connection_pool'
7
- require 'data_mapper/query'
8
-
9
- module DataMapper
10
-
11
- # An Adapter is really a Factory for three types of object,
12
- # so they can be selectively sub-classed where needed.
13
- #
14
- # The first type is a Query. The Query is an object describing
15
- # the database-specific operations we wish to perform, in an
16
- # abstract manner. For example: While most if not all databases
17
- # support a mechanism for limiting the size of results returned,
18
- # some use a "LIMIT" keyword, while others use a "TOP" keyword.
19
- # We can set a SelectStatement#limit field then, and allow
20
- # the adapter to override the underlying SQL generated.
21
- # Refer to DataMapper::Queries.
22
- #
23
- # The final type provided is a DataMapper::Transaction.
24
- # Transactions are duck-typed Connections that span multiple queries.
25
- #
26
- # Note: It is assumed that the Adapter implements it's own
27
- # ConnectionPool if any since some libraries implement their own at
28
- # a low-level, and it wouldn't make sense to pay a performance
29
- # cost twice by implementing a secondary pool in the DataMapper itself.
30
- # If the library being adapted does not provide such functionality,
31
- # DataMapper::Support::ConnectionPool can be used.
32
- module Adapters
33
-
34
- # You must inherit from the DoAdapter, and implement the
35
- # required methods to adapt a database library for use with the DataMapper.
36
- #
37
- # NOTE: By inheriting from DoAdapter, you get a copy of all the
38
- # standard sub-modules (Quoting, Coersion and Queries) in your own Adapter.
39
- # You can extend and overwrite these copies without affecting the originals.
40
- class DataObjectAdapter < AbstractAdapter
41
-
42
- $LOAD_PATH << (DM_PLUGINS_ROOT + '/dataobjects')
43
-
44
- FIND_OPTIONS = [
45
- :select, :offset, :limit, :class, :include, :shallow_include, :reload, :conditions, :order, :intercept_load
46
- ]
47
-
48
- TABLE_QUOTING_CHARACTER = '`'.freeze
49
- COLUMN_QUOTING_CHARACTER = '`'.freeze
50
-
51
- SYNTAX = {
52
- :now => 'NOW()'.freeze
53
- }
54
-
55
- def initialize(configuration)
56
- super
57
- @connection_pool = Support::ConnectionPool.new { create_connection }
58
- end
59
-
60
- def activated?
61
- @activated
62
- end
63
-
64
- def activate!
65
- @activated = true
66
- schema.activate!
67
- end
68
-
69
- def create_connection
70
- raise NotImplementedError.new
71
- end
72
-
73
- def batch_insertable?
74
- true
75
- end
76
-
77
- # Yields an available connection. Flushes the connection-pool and reconnects
78
- # if the connection returns an error.
79
- def connection
80
- begin
81
- # Yield the appropriate connection
82
- @connection_pool.hold { |active_connection| yield(active_connection) }
83
- rescue => execution_error
84
- # Log error on failure
85
- logger.error { execution_error }
86
-
87
- # Close all open connections, assuming that if one
88
- # had an error, it's likely due to a lost connection,
89
- # in which case all connections are likely broken.
90
- flush_connections!
91
-
92
- raise execution_error
93
- end
94
- end
95
-
96
- # Close any open connections.
97
- def flush_connections!
98
- @connection_pool.available_connections.each do |active_connection|
99
- begin
100
- active_connection.close
101
- rescue => close_connection_error
102
- # An error on closing the connection is almost expected
103
- # if the socket is broken.
104
- logger.warn { close_connection_error }
105
- end
106
- end
107
-
108
- # Reopen fresh connections.
109
- @connection_pool.instance_variable_set('@created_count', 0)
110
- @connection_pool.available_connections.clear
111
- end
112
-
113
- def transaction(&block)
114
- raise NotImplementedError.new
115
- end
116
-
117
- def query(*args)
118
- db = create_connection
119
-
120
- command = db.create_command(args.shift)
121
-
122
- reader = command.execute_reader(*args)
123
- fields = reader.fields.map { |field| Inflector.underscore(field).to_sym }
124
- results = []
125
-
126
- if fields.size > 1
127
- struct = Struct.new(*fields)
128
-
129
- reader.each do
130
- results << struct.new(*reader.current_row)
131
- end
132
- else
133
- reader.each do
134
- results << reader.item(0)
135
- end
136
- end
137
-
138
- return results
139
- rescue => e
140
- logger.error { e }
141
- raise e
142
- ensure
143
- reader.close if reader
144
- db.close
145
- end
146
-
147
- def execute(*args)
148
- db = create_connection
149
- command = db.create_command(args.shift)
150
- return command.execute_non_query(*args)
151
- rescue => e
152
- logger.error { e }
153
- raise e
154
- ensure
155
- db.close
156
- end
157
-
158
- def handle_error(error)
159
- raise error
160
- end
161
-
162
- def schema
163
- @schema || ( @schema = self.class::Mappings::Schema.new(self, @configuration.database) )
164
- end
165
-
166
- def column_exists_for_table?(table_name, column_name)
167
- connection do |db|
168
- table = self.table(table_name)
169
- command = db.create_command(table.to_column_exists_sql)
170
- command.execute_reader(table.name, column_name, table.schema.name) do |reader|
171
- reader.any? { reader.item(1) == column_name.to_s }
172
- end
173
- end
174
- end
175
-
176
- def delete(database_context, instance)
177
- table = self.table(instance)
178
-
179
- if instance.is_a?(Class)
180
- table.delete_all!
181
- else
182
- callback(instance, :before_destroy)
183
-
184
- table.associations.each do |association|
185
- instance.send(association.name).deactivate unless association.is_a?(::DataMapper::Associations::BelongsToAssociation)
186
- end
187
-
188
- if table.paranoid?
189
- instance.instance_variable_set(table.paranoid_column.instance_variable_name, Time::now)
190
- instance.save
191
- else
192
- if connection do |db|
193
- command = db.create_command("DELETE FROM #{table.to_sql} WHERE #{table.key.to_sql} = ?")
194
- command.execute_non_query(instance.key).to_i > 0
195
- end # connection do...end # if continued below:
196
- instance.instance_variable_set(:@new_record, true)
197
- instance.database_context = database_context
198
- instance.original_values.clear
199
- database_context.identity_map.delete(instance)
200
- callback(instance, :after_destroy)
201
- end
202
- end
203
- end
204
- end
205
-
206
- def save(database_context, instance, validate = true, cleared = Set.new)
207
- case instance
208
- when Class then
209
- table(instance).create!
210
- table(instance).activate_associations!
211
- when Mappings::Table then instance.create!
212
- when DataMapper::Persistence then
213
- event = instance.new_record? ? :create : :update
214
-
215
- return false if (validate && !instance.validate_recursively(event, Set.new)) || cleared.include?(instance)
216
- cleared << instance
217
-
218
- callback(instance, :before_save)
219
-
220
- return true unless instance.new_record? || instance.dirty?
221
-
222
- result = send(event, database_context, instance)
223
-
224
- instance.database_context = database_context
225
- instance.attributes.each_pair do |name, value|
226
- instance.original_values[name] = value
227
- end
228
-
229
- instance.loaded_associations.each do |association|
230
- association.save_without_validation(database_context, cleared) if association.dirty?
231
- end
232
-
233
- callback(instance, :after_save)
234
- result
235
- end
236
- rescue => error
237
- logger.error(error)
238
- raise error
239
- end
240
-
241
- def save_without_validation(database_context, instance, cleared = Set.new)
242
- save(database_context, instance, false, cleared)
243
- end
244
-
245
- def update(database_context, instance)
246
- callback(instance, :before_update)
247
-
248
- instance = update_magic_properties(database_context, instance)
249
-
250
- table = self.table(instance)
251
- attributes = instance.dirty_attributes
252
- parameters = []
253
-
254
- unless attributes.empty?
255
- sql = "UPDATE " << table.to_sql << " SET "
256
-
257
- sql << attributes.map do |key, value|
258
- parameters << value
259
- "#{table[key].to_sql} = ?"
260
- end.join(', ')
261
-
262
- sql << " WHERE #{table.key.to_sql} = ?"
263
- parameters << instance.key
264
-
265
- result = connection do |db|
266
- db.create_command(sql).execute_non_query(*parameters)
267
- end
268
-
269
- # BUG: do_mysql returns inaccurate affected row counts for UPDATE statements.
270
- if true || result.to_i > 0
271
- callback(instance, :after_update)
272
- return true
273
- else
274
- return false
275
- end
276
- else
277
- true
278
- end
279
- end
280
-
281
- def empty_insert_sql
282
- "DEFAULT VALUES"
283
- end
284
-
285
- def create(database_context, instance)
286
- callback(instance, :before_create)
287
-
288
- instance = update_magic_properties(database_context, instance)
289
-
290
- table = self.table(instance)
291
- attributes = instance.dirty_attributes
292
-
293
- if table.multi_class?
294
- instance.instance_variable_set(
295
- table[:type].instance_variable_name,
296
- attributes[:type] = instance.class.name
297
- )
298
- end
299
-
300
- keys = []
301
- values = []
302
- attributes.each_pair do |key, value|
303
- raise ArgumentError.new("#{value.inspect} is not a valid value for #{key.inspect}") if value.is_a?(Array)
304
-
305
- keys << table[key].to_sql
306
- values << value
307
- end
308
-
309
- sql = if keys.size > 0
310
- "INSERT INTO #{table.to_sql} (#{keys.join(', ')}) VALUES ?"
311
- else
312
- "INSERT INTO #{table.to_sql} #{self.empty_insert_sql}"
313
- end
314
-
315
- result = connection do |db|
316
- db.create_command(sql).execute_non_query(values)
317
- end
318
-
319
- if result.to_i > 0
320
- instance.instance_variable_set(:@new_record, false)
321
- instance.key = result.last_insert_row if table.key.serial? && !attributes.include?(table.key.name)
322
- database_context.identity_map.set(instance)
323
- callback(instance, :after_create)
324
- return true
325
- else
326
- return false
327
- end
328
- end
329
-
330
- MAGIC_PROPERTIES = {
331
- :updated_at => lambda { self.updated_at = Time::now },
332
- :updated_on => lambda { self.updated_on = Date::today },
333
- :created_at => lambda { self.created_at ||= Time::now },
334
- :created_on => lambda { self.created_on ||= Date::today }
335
- }
336
-
337
- def update_magic_properties(database_context, instance)
338
- instance.class.properties.find_all { |property| MAGIC_PROPERTIES.has_key?(property.name) }.each do |property|
339
- instance.instance_eval(&MAGIC_PROPERTIES[property.name])
340
- end
341
- instance
342
- end
343
-
344
- def load(database_context, klass, options)
345
- self.class::Commands::LoadCommand.new(self, database_context, klass, options).call
346
- end
347
-
348
- def get(database_context, klass, keys)
349
- table = self.table(klass)
350
- instance_id = table.key.type_cast_value(keys.first)
351
- instance = database_context.identity_map.get(klass, instance_id)
352
-
353
- return instance if instance
354
-
355
- column_indexes = {}
356
- select_columns = []
357
-
358
- table.columns.each_with_index do |column, i|
359
- column_indexes[column] = i
360
- select_columns << column.to_sql
361
- end
362
-
363
- sql = "SELECT #{select_columns.join(', ')} FROM #{table.to_sql} WHERE #{table.keys.map { |key| "#{key.to_sql} = ?" }.join(' AND ')}"
364
-
365
- connection do |db|
366
- reader = nil
367
- begin
368
- reader = db.create_command(sql).execute_reader(*keys)
369
-
370
- if reader.has_rows?
371
-
372
- instance_type = klass
373
-
374
- if table.multi_class? && table.type_column
375
- value = reader.item(column_indexes[table.type_column])
376
- instance_type = table.type_column.type_cast_value(value) unless value.blank?
377
- end
378
-
379
- if instance.nil?
380
- instance = instance_type.allocate()
381
- instance.instance_variable_set(:@__key, instance_id)
382
- instance.instance_variable_set(:@new_record, false)
383
- database_context.identity_map.set(instance)
384
- elsif instance.new_record?
385
- instance.instance_variable_set(:@__key, instance_id)
386
- instance.instance_variable_set(:@new_record, false)
387
- database_context.identity_map.set(instance)
388
- end
389
-
390
- instance.database_context = database_context
391
-
392
- instance_type.callbacks.execute(:before_materialize, instance)
393
-
394
- originals = instance.original_values
395
-
396
- column_indexes.each_pair do |column, i|
397
- value = column.type_cast_value(reader.item(i))
398
- instance.instance_variable_set(column.instance_variable_name, value)
399
-
400
- case value
401
- when String, Date, Time then originals[column.name] = value.dup
402
- else originals[column.name] = value
403
- end
404
- end
405
-
406
- instance.loaded_set = [instance]
407
-
408
- instance_type.callbacks.execute(:after_materialize, instance)
409
- end # if reader.has_rows?
410
- ensure
411
- reader.close if reader && reader.open?
412
- end
413
- end # connection
414
-
415
- return instance
416
- end
417
-
418
- def table(instance)
419
- case instance
420
- when DataMapper::Adapters::Sql::Mappings::Table then instance
421
- when DataMapper::Persistence then schema[instance.class]
422
- when Class, String then schema[instance]
423
- else raise "Don't know how to map #{instance.inspect} to a table."
424
- end
425
- end
426
-
427
- def callback(instance, callback_name)
428
- instance.class.callbacks.execute(callback_name, instance)
429
- end
430
-
431
- # This callback copies and sub-classes modules and classes
432
- # in the DoAdapter to the inherited class so you don't
433
- # have to copy and paste large blocks of code from the
434
- # DoAdapter.
435
- #
436
- # Basically, when inheriting from the DoAdapter, you
437
- # aren't just inheriting a single class, you're inheriting
438
- # a whole graph of Types. For convenience.
439
- def self.inherited(base)
440
-
441
- commands = base.const_set('Commands', Module.new)
442
-
443
- Sql::Commands.constants.each do |name|
444
- commands.const_set(name, Class.new(Sql::Commands.const_get(name)))
445
- end
446
-
447
- mappings = base.const_set('Mappings', Module.new)
448
-
449
- Sql::Mappings.constants.each do |name|
450
- mappings.const_set(name, Class.new(Sql::Mappings.const_get(name)))
451
- end
452
-
453
- base.const_set('TYPES', TYPES.dup)
454
- base.const_set('FIND_OPTIONS', FIND_OPTIONS.dup)
455
- base.const_set('SYNTAX', SYNTAX.dup)
456
-
457
- super
458
- end
459
-
460
- TYPES = {
461
- :integer => 'int'.freeze,
462
- :string => 'varchar'.freeze,
463
- :text => 'text'.freeze,
464
- :class => 'varchar'.freeze,
465
- :decimal => 'decimal'.freeze,
466
- :float => 'float'.freeze,
467
- :datetime => 'datetime'.freeze,
468
- :date => 'date'.freeze,
469
- :boolean => 'boolean'.freeze,
470
- :object => 'text'.freeze
471
- }
472
-
473
- include Sql
474
- include Quoting
475
- include Coersion
476
-
477
- end # class DoAdapter
478
-
479
- end # module Adapters
480
- end # module DataMapper