datamapper 0.3.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
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