datamapper 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +31 -1
- data/MIT-LICENSE +1 -1
- data/README +9 -1
- data/example.rb +23 -15
- data/lib/data_mapper.rb +5 -0
- data/lib/data_mapper/adapters/abstract_adapter.rb +9 -207
- data/lib/data_mapper/adapters/mysql_adapter.rb +132 -108
- data/lib/data_mapper/adapters/postgresql_adapter.rb +242 -0
- data/lib/data_mapper/adapters/sql/coersion.rb +74 -0
- data/lib/data_mapper/adapters/sql/commands/advanced_load_command.rb +140 -0
- data/lib/data_mapper/adapters/sql/commands/conditions.rb +161 -0
- data/lib/data_mapper/adapters/sql/commands/delete_command.rb +113 -0
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +296 -0
- data/lib/data_mapper/adapters/sql/commands/save_command.rb +141 -0
- data/lib/data_mapper/adapters/sql/commands/table_exists_command.rb +33 -0
- data/lib/data_mapper/adapters/sql/mappings/column.rb +91 -0
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +30 -0
- data/lib/data_mapper/adapters/sql/mappings/table.rb +143 -0
- data/lib/data_mapper/adapters/sql/quoting.rb +38 -0
- data/lib/data_mapper/adapters/sql_adapter.rb +163 -0
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +155 -116
- data/lib/data_mapper/associations.rb +2 -0
- data/lib/data_mapper/associations/advanced_has_many_association.rb +55 -0
- data/lib/data_mapper/associations/belongs_to_association.rb +2 -2
- data/lib/data_mapper/associations/has_many_association.rb +3 -3
- data/lib/data_mapper/associations/has_one_association.rb +2 -2
- data/lib/data_mapper/base.rb +30 -11
- data/lib/data_mapper/callbacks.rb +4 -1
- data/lib/data_mapper/database.rb +8 -41
- data/lib/data_mapper/identity_map.rb +23 -3
- data/lib/data_mapper/session.rb +34 -186
- data/lib/data_mapper/{extensions → support}/active_record_impersonation.rb +16 -12
- data/lib/data_mapper/support/blank.rb +35 -0
- data/lib/data_mapper/support/connection_pool.rb +2 -1
- data/lib/data_mapper/support/string.rb +27 -0
- data/lib/data_mapper/support/struct.rb +26 -0
- data/lib/data_mapper/validations/unique_validator.rb +1 -3
- data/lib/data_mapper/validations/validation_helper.rb +1 -1
- data/performance.rb +24 -7
- data/profile_data_mapper.rb +24 -2
- data/rakefile.rb +2 -2
- data/spec/basic_finder.rb +2 -2
- data/spec/belongs_to.rb +1 -1
- data/spec/delete_command_spec.rb +9 -0
- data/spec/fixtures/zoos.yaml +4 -0
- data/spec/has_many.rb +1 -1
- data/spec/load_command_spec.rb +44 -0
- data/spec/models/zoo.rb +2 -0
- data/spec/save_command_spec.rb +13 -0
- data/spec/spec_helper.rb +10 -1
- data/spec/support/string_spec.rb +7 -0
- data/spec/validates_confirmation_of.rb +1 -1
- data/spec/validates_format_of.rb +1 -1
- data/spec/validates_length_of.rb +1 -1
- data/spec/validations.rb +1 -1
- metadata +23 -20
- data/lib/data_mapper/extensions/callback_helpers.rb +0 -35
- data/lib/data_mapper/loaded_set.rb +0 -45
- data/lib/data_mapper/mappings/column.rb +0 -78
- data/lib/data_mapper/mappings/schema.rb +0 -28
- data/lib/data_mapper/mappings/table.rb +0 -99
- data/lib/data_mapper/queries/conditions.rb +0 -141
- data/lib/data_mapper/queries/connection.rb +0 -34
- data/lib/data_mapper/queries/create_table_statement.rb +0 -38
- data/lib/data_mapper/queries/delete_statement.rb +0 -17
- data/lib/data_mapper/queries/drop_table_statement.rb +0 -17
- data/lib/data_mapper/queries/insert_statement.rb +0 -29
- data/lib/data_mapper/queries/reader.rb +0 -42
- data/lib/data_mapper/queries/result.rb +0 -19
- data/lib/data_mapper/queries/select_statement.rb +0 -103
- data/lib/data_mapper/queries/table_exists_statement.rb +0 -17
- data/lib/data_mapper/queries/truncate_table_statement.rb +0 -17
- data/lib/data_mapper/queries/update_statement.rb +0 -25
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'data_mapper/associations/has_many_association'
|
2
|
+
require 'data_mapper/associations/advanced_has_many_association'
|
2
3
|
require 'data_mapper/associations/belongs_to_association'
|
3
4
|
require 'data_mapper/associations/has_one_association'
|
4
5
|
require 'data_mapper/associations/has_and_belongs_to_many_association'
|
@@ -9,6 +10,7 @@ module DataMapper
|
|
9
10
|
def self.included(base)
|
10
11
|
base.class_eval do
|
11
12
|
include DataMapper::Associations::HasMany
|
13
|
+
include DataMapper::Associations::AdvancedHasMany
|
12
14
|
include DataMapper::Associations::BelongsTo
|
13
15
|
include DataMapper::Associations::HasOne
|
14
16
|
include DataMapper::Associations::HasAndBelongsToMany
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Associations
|
3
|
+
|
4
|
+
class AdvancedHasManyAssociation
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(klass, association_name, options)
|
8
|
+
@association_name = association_name.to_sym
|
9
|
+
@options = options
|
10
|
+
|
11
|
+
# Define the association instance method (i.e. Project#tasks)
|
12
|
+
klass.class_eval <<-EOS
|
13
|
+
def #{association_name}
|
14
|
+
@#{association_name} || (@#{association_name} = HasManyAssociation.new(self, "#{association_name}", #{options.inspect}))
|
15
|
+
end
|
16
|
+
EOS
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
@association_name
|
21
|
+
end
|
22
|
+
|
23
|
+
def constant
|
24
|
+
@associated_class || @associated_class = if @options.has_key?(:class) || @options.has_key?(:class_name)
|
25
|
+
associated_class_name = (@options[:class] || @options[:class_name])
|
26
|
+
if associated_class_name.kind_of?(String)
|
27
|
+
Kernel.const_get(Inflector.classify(associated_class_name))
|
28
|
+
else
|
29
|
+
associated_class_name
|
30
|
+
end
|
31
|
+
else
|
32
|
+
Kernel.const_get(Inflector.classify(association_name))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def foreign_key
|
37
|
+
@foreign_key || (@foreign_key = (@options[:foreign_key] || @instance.session.schema[@instance.class].default_foreign_key))
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
module AdvancedHasMany
|
43
|
+
def self.included(base)
|
44
|
+
base.extend(ClassMethods)
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
def advanced_has_many(association_name, options = {})
|
49
|
+
database.schema[self].associations << AdvancedHasManyAssociation.new(self, association_name, options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -60,10 +60,10 @@ module DataMapper
|
|
60
60
|
setter_method = "#{@association_name}=".to_sym
|
61
61
|
instance_variable_name = "@#{foreign_key}".to_sym
|
62
62
|
|
63
|
-
set = @instance.loaded_set.
|
63
|
+
set = @instance.loaded_set.group_by { |instance| instance.instance_variable_get(instance_variable_name) }
|
64
64
|
|
65
65
|
# Fetch the foreign objects for all instances in the current object's loaded-set.
|
66
|
-
@instance.session.
|
66
|
+
@instance.session.all(@associated_class, :id => set.keys).each do |owner|
|
67
67
|
set[owner.key].each do |instance|
|
68
68
|
instance.send(setter_method, owner)
|
69
69
|
end
|
@@ -22,7 +22,7 @@ module DataMapper
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.setup(klass, association_name, options)
|
25
|
-
|
25
|
+
|
26
26
|
# Define the association instance method (i.e. Project#tasks)
|
27
27
|
klass.class_eval <<-EOS
|
28
28
|
def #{association_name}
|
@@ -57,10 +57,10 @@ module DataMapper
|
|
57
57
|
# Temp variable for the instance variable name.
|
58
58
|
instance_variable_name = "@#{foreign_key}".to_sym
|
59
59
|
|
60
|
-
set = @instance.loaded_set.
|
60
|
+
set = @instance.loaded_set.group_by { |instance| instance.key }
|
61
61
|
|
62
62
|
# Fetch the foreign objects for all instances in the current object's loaded-set.
|
63
|
-
@instance.session.
|
63
|
+
@instance.session.all(@associated_class, foreign_key.to_sym => set.keys).group_by do |association|
|
64
64
|
association.instance_variable_get(instance_variable_name)
|
65
65
|
end.each_pair do |id, results|
|
66
66
|
set[id].first.send(@association_name).set(results)
|
@@ -58,10 +58,10 @@ module DataMapper
|
|
58
58
|
setter_method = "#{@association_name}=".to_sym
|
59
59
|
instance_variable_name = "@#{foreign_key}".to_sym
|
60
60
|
|
61
|
-
set = @instance.loaded_set.
|
61
|
+
set = @instance.loaded_set.group_by { |instance| instance.key }
|
62
62
|
|
63
63
|
# Fetch the foreign objects for all instances in the current object's loaded-set.
|
64
|
-
@instance.session.
|
64
|
+
@instance.session.all(@associated_class, foreign_key => set.keys).each do |association|
|
65
65
|
set[association.instance_variable_get(instance_variable_name)].first.send(setter_method, association)
|
66
66
|
end
|
67
67
|
end
|
data/lib/data_mapper/base.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'data_mapper/unit_of_work'
|
2
|
-
require 'data_mapper/
|
3
|
-
require 'data_mapper/extensions/callback_helpers'
|
2
|
+
require 'data_mapper/support/active_record_impersonation'
|
4
3
|
require 'data_mapper/validations/validation_helper'
|
5
4
|
require 'data_mapper/associations'
|
5
|
+
require 'data_mapper/callbacks'
|
6
6
|
|
7
7
|
module DataMapper
|
8
8
|
|
@@ -12,9 +12,8 @@ module DataMapper
|
|
12
12
|
attr_accessor :loaded_set
|
13
13
|
|
14
14
|
include UnitOfWork
|
15
|
-
include
|
16
|
-
include
|
17
|
-
include Extensions::ValidationHelper
|
15
|
+
include Support::ActiveRecordImpersonation
|
16
|
+
include Validations::ValidationHelper
|
18
17
|
include Associations
|
19
18
|
|
20
19
|
def self.inherited(klass)
|
@@ -93,7 +92,7 @@ module DataMapper
|
|
93
92
|
value = instance_variable_get(column.instance_variable_name)
|
94
93
|
return value unless value.nil?
|
95
94
|
|
96
|
-
session.
|
95
|
+
session.all(self.class, :select => [:id, name], :reload => true, :id => loaded_set.map(&:id)).each do |instance|
|
97
96
|
(class << self; self end).send(:attr_accessor, name)
|
98
97
|
end
|
99
98
|
|
@@ -127,7 +126,7 @@ module DataMapper
|
|
127
126
|
end
|
128
127
|
|
129
128
|
def self.foreign_key
|
130
|
-
|
129
|
+
String::memoized_underscore(self.name) + "_id"
|
131
130
|
end
|
132
131
|
|
133
132
|
def inspect
|
@@ -147,14 +146,34 @@ module DataMapper
|
|
147
146
|
end
|
148
147
|
|
149
148
|
def session
|
150
|
-
@session
|
149
|
+
@session || ( @session = database )
|
151
150
|
end
|
152
151
|
|
153
152
|
def key
|
154
|
-
|
155
|
-
|
153
|
+
@__key || @__key = begin
|
154
|
+
key_column = session.schema[self.class].key
|
155
|
+
key_column.type_cast_value(instance_variable_get(key_column.instance_variable_name))
|
156
|
+
end
|
156
157
|
end
|
157
|
-
|
158
|
+
|
159
|
+
# Callbacks associated with this class.
|
160
|
+
def self.callbacks
|
161
|
+
@callbacks || ( @callbacks = Callbacks.new )
|
162
|
+
end
|
163
|
+
|
164
|
+
# Declare helpers for the standard callbacks
|
165
|
+
DataMapper::Callbacks::EVENTS.each do |name|
|
166
|
+
class_eval <<-EOS
|
167
|
+
def self.#{name}(string = nil, &block)
|
168
|
+
if string.nil?
|
169
|
+
callbacks.add(:#{name}, &block)
|
170
|
+
else
|
171
|
+
callbacks.add(:#{name}, string)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
EOS
|
175
|
+
end
|
176
|
+
|
158
177
|
end
|
159
178
|
|
160
179
|
end
|
@@ -12,7 +12,10 @@ module DataMapper
|
|
12
12
|
]
|
13
13
|
|
14
14
|
def initialize
|
15
|
-
@callbacks = Hash.new
|
15
|
+
@callbacks = Hash.new do |h,k|
|
16
|
+
raise 'Callback names must be Symbols' unless k.kind_of?(Symbol)
|
17
|
+
h[k] = []
|
18
|
+
end
|
16
19
|
end
|
17
20
|
|
18
21
|
alias ruby_method_missing method_missing
|
data/lib/data_mapper/database.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require 'data_mapper/session'
|
3
|
-
require 'data_mapper/mappings/schema'
|
4
3
|
|
5
4
|
# Delegates to DataMapper::database.
|
6
5
|
# Will not overwrite if a method of the same name is pre-defined.
|
@@ -18,11 +17,12 @@ module DataMapper
|
|
18
17
|
# a new Session.
|
19
18
|
def self.database(name = :default)
|
20
19
|
unless block_given?
|
21
|
-
Database.context.last || Session.new(Database[name])
|
20
|
+
Database.context.last || Session.new(Database[name].adapter)
|
22
21
|
else
|
23
|
-
Database.context.push(Session.new(Database[name]))
|
24
|
-
yield
|
22
|
+
Database.context.push(Session.new(Database[name].adapter))
|
23
|
+
result = yield(Database.context.last)
|
25
24
|
Database.context.pop
|
25
|
+
result
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -51,28 +51,8 @@ module DataMapper
|
|
51
51
|
|
52
52
|
def initialize(name)
|
53
53
|
@name = name
|
54
|
-
end
|
55
|
-
|
56
|
-
# Shortcut to adapter.class::Queries::FooStatement.new
|
57
|
-
def method_missing(sym, *args)
|
58
|
-
return super if sym.to_s !~ /_statement$/
|
59
|
-
@adapter.class::Queries.const_get(Inflector.classify(sym.to_s)).new(self, *args)
|
60
|
-
end
|
61
|
-
|
62
|
-
def syntax(token)
|
63
|
-
@adapter.class::SYNTAX[token]
|
64
|
-
end
|
65
|
-
|
66
|
-
def [](klass_or_table_name)
|
67
|
-
schema[klass_or_table_name]
|
68
|
-
end
|
69
|
-
|
70
|
-
def schema
|
71
|
-
@schema ||= Mappings::Schema.new(self)
|
72
54
|
end
|
73
55
|
|
74
|
-
class ConditionEscapeError < StandardError; end
|
75
|
-
|
76
56
|
attr_reader :name
|
77
57
|
|
78
58
|
def adapter(value = nil)
|
@@ -80,12 +60,9 @@ module DataMapper
|
|
80
60
|
|
81
61
|
raise ArgumentError.new('The adapter is readonly after being set') unless @adapter.nil?
|
82
62
|
|
83
|
-
require "data_mapper/adapters/#{
|
63
|
+
require "data_mapper/adapters/#{String::memoized_underscore(value)}_adapter"
|
84
64
|
adapter_class = Adapters::const_get(Inflector.classify(value) + "Adapter")
|
85
65
|
|
86
|
-
(class << self; self end).send(:include, adapter_class::Quoting)
|
87
|
-
(class << self; self end).send(:include, adapter_class::Coersion)
|
88
|
-
|
89
66
|
@adapter = adapter_class.new(self)
|
90
67
|
end
|
91
68
|
|
@@ -94,6 +71,9 @@ module DataMapper
|
|
94
71
|
def username(value = nil); value.nil? ? @username : @username = value end
|
95
72
|
def password(value = nil); value.nil? ? (@password || '') : @password = value end
|
96
73
|
|
74
|
+
# single_threaded mode is disabled by default currently since it's buggy.
|
75
|
+
def single_threaded(value = nil); value.nil? ? (@single_threaded.nil? ? @single_threaded = false : @single_threaded) : @single_threaded = value end
|
76
|
+
|
97
77
|
def log(value = nil)
|
98
78
|
@log = value unless value.nil?
|
99
79
|
|
@@ -116,19 +96,6 @@ module DataMapper
|
|
116
96
|
@log_stream = value
|
117
97
|
end
|
118
98
|
|
119
|
-
def connection
|
120
|
-
@adapter.connection do |db|
|
121
|
-
results = yield(db)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def query(sql)
|
126
|
-
connection { |db| db.query(sql) }
|
127
|
-
end
|
128
|
-
|
129
|
-
def execute(sql)
|
130
|
-
connection { |db| db.execute(sql) }
|
131
|
-
end
|
132
99
|
end
|
133
100
|
|
134
101
|
end
|
@@ -1,20 +1,40 @@
|
|
1
1
|
require 'data_mapper/support/weak_hash'
|
2
2
|
|
3
3
|
module DataMapper
|
4
|
+
|
5
|
+
# Tracks objects to help ensure that each object gets loaded only once.
|
6
|
+
# See: http://www.martinfowler.com/eaaCatalog/identityMap.html
|
4
7
|
class IdentityMap
|
5
8
|
|
6
9
|
def initialize
|
7
|
-
|
10
|
+
# WeakHash is much more expensive, and not necessary if the IdentityMap is tied to Session instead of Database.
|
11
|
+
# @cache = Hash.new { |h,k| h[k] = Support::WeakHash.new }
|
12
|
+
@cache = Hash.new { |h,k| h[k] = Hash.new }
|
8
13
|
end
|
9
14
|
|
15
|
+
# Pass a Class and a key, and to retrieve an instance.
|
16
|
+
# If the instance isn't found, nil is returned.
|
10
17
|
def get(klass, key)
|
11
18
|
@cache[klass][key]
|
12
19
|
end
|
13
20
|
|
21
|
+
# Pass an instance to add it to the IdentityMap.
|
22
|
+
# The instance must have an assigned key.
|
14
23
|
def set(instance)
|
15
|
-
|
24
|
+
instance_key = instance.key
|
25
|
+
raise "Can't store an instance with a nil key in the IdentityMap" if instance_key.nil?
|
16
26
|
|
17
|
-
@cache[instance.class][
|
27
|
+
@cache[instance.class][instance_key] = instance
|
28
|
+
end
|
29
|
+
|
30
|
+
# Remove an instance from the IdentityMap.
|
31
|
+
def delete(instance)
|
32
|
+
@cache[instance.class].delete(instance.key)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Clears a particular set of classes from the IdentityMap.
|
36
|
+
def clear!(klass)
|
37
|
+
@cache.delete(klass)
|
18
38
|
end
|
19
39
|
|
20
40
|
end
|
data/lib/data_mapper/session.rb
CHANGED
@@ -1,240 +1,88 @@
|
|
1
|
-
require 'data_mapper/loaded_set'
|
2
1
|
require 'data_mapper/identity_map'
|
3
2
|
|
4
3
|
module DataMapper
|
5
4
|
|
6
5
|
class Session
|
7
|
-
|
8
|
-
FIND_OPTIONS = [
|
9
|
-
:select, :limit, :class, :include, :reload, :conditions, :order
|
10
|
-
]
|
11
6
|
|
12
7
|
class MaterializationError < StandardError
|
13
8
|
end
|
14
9
|
|
15
|
-
|
16
|
-
|
10
|
+
attr_reader :adapter
|
11
|
+
|
12
|
+
def initialize(adapter)
|
13
|
+
@adapter = adapter
|
17
14
|
end
|
18
15
|
|
19
16
|
def identity_map
|
20
17
|
@identity_map || ( @identity_map = IdentityMap.new )
|
21
18
|
end
|
22
19
|
|
23
|
-
def
|
24
|
-
|
20
|
+
def first(klass, *args, &b)
|
21
|
+
id = nil
|
22
|
+
options = nil
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
if args.empty? # No id, no options
|
25
|
+
options = { :limit => 1 }
|
26
|
+
elsif args.size == 2 && args.last.kind_of?(Hash) # id AND options
|
27
|
+
options = args.last.merge(:id => args.first)
|
28
|
+
elsif args.size == 1 # id OR options
|
29
|
+
if args.first.kind_of?(Hash)
|
30
|
+
options = args.first.merge(:limit => 1) # no id, add limit
|
31
31
|
else
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
case results
|
36
|
-
when Array then results.each { |instance| instance.session = self }
|
37
|
-
when Base then results.session = self
|
38
|
-
end
|
39
|
-
return results
|
40
|
-
end
|
41
|
-
|
42
|
-
def first(options)
|
43
|
-
if options.has_id? && !options.reload?
|
44
|
-
instance = identity_map.get(options.klass, options.instance_id)
|
45
|
-
return instance unless instance.nil?
|
46
|
-
end
|
47
|
-
|
48
|
-
reader = @database.query(options)
|
49
|
-
instance = reader.eof? ? nil : load(options, reader.next)
|
50
|
-
reader.close
|
51
|
-
return instance
|
52
|
-
rescue DatabaseError => de
|
53
|
-
de.options = options
|
54
|
-
raise de
|
55
|
-
end
|
56
|
-
|
57
|
-
def all(options)
|
58
|
-
set = LoadedSet.new(@database)
|
59
|
-
reader = @database.query(options)
|
60
|
-
instances = reader.map do |hash|
|
61
|
-
load(options, hash, set)
|
62
|
-
end
|
63
|
-
reader.close
|
64
|
-
return instances
|
65
|
-
rescue => error
|
66
|
-
@database.log.error(error)
|
67
|
-
raise error
|
68
|
-
end
|
69
|
-
|
70
|
-
def load(options, hash, set = LoadedSet.new(@database))
|
71
|
-
|
72
|
-
instance_class = unless hash['type'].nil?
|
73
|
-
Kernel::const_get(hash['type'])
|
32
|
+
options = { :id => args.first } # no options, set id
|
33
|
+
end
|
74
34
|
else
|
75
|
-
options
|
35
|
+
raise ArgumentError.new('Session#first takes a class, and optional type_or_id and/or options arguments')
|
76
36
|
end
|
77
37
|
|
78
|
-
|
38
|
+
options.merge!(b.to_hash) if block_given?
|
79
39
|
|
80
|
-
|
81
|
-
instance = identity_map.get(instance_class, instance_id)
|
82
|
-
|
83
|
-
if instance.nil? || options.reload?
|
84
|
-
instance ||= instance_class.new
|
85
|
-
instance.class.callbacks.execute(:before_materialize, instance)
|
86
|
-
|
87
|
-
instance.instance_variable_set(:@new_record, false)
|
88
|
-
hash.each_pair do |name_as_string,raw_value|
|
89
|
-
name = name_as_string.to_sym
|
90
|
-
if column = mapping.find_by_column_name(name)
|
91
|
-
value = column.type_cast_value(raw_value)
|
92
|
-
instance.instance_variable_set(column.instance_variable_name, value)
|
93
|
-
else
|
94
|
-
instance.instance_variable_set("@#{name}", value)
|
95
|
-
end
|
96
|
-
instance.original_hashes[name] = value.hash
|
97
|
-
end
|
98
|
-
|
99
|
-
instance.class.callbacks.execute(:after_materialize, instance)
|
100
|
-
|
101
|
-
identity_map.set(instance)
|
102
|
-
end
|
103
|
-
|
104
|
-
instance.instance_variable_set(:@loaded_set, set)
|
105
|
-
set.instances << instance
|
106
|
-
return instance
|
107
|
-
end
|
108
|
-
|
109
|
-
def save(instance)
|
110
|
-
return false unless instance.dirty?
|
111
|
-
instance.class.callbacks.execute(:before_save, instance)
|
112
|
-
result = instance.new_record? ? insert(instance) : update(instance)
|
113
|
-
instance.session = self
|
114
|
-
instance.class.callbacks.execute(:after_save, instance)
|
115
|
-
result.success?
|
40
|
+
@adapter.load(self, klass, options)
|
116
41
|
end
|
117
42
|
|
118
|
-
def
|
119
|
-
|
120
|
-
result = @database.execute(@database.insert_statement(instance))
|
121
|
-
|
122
|
-
if result.success?
|
123
|
-
instance.instance_variable_set(:@new_record, false)
|
124
|
-
instance.instance_variable_set(:@id, inserted_id || result.last_inserted_id)
|
125
|
-
calculate_original_hashes(instance)
|
126
|
-
identity_map.set(instance)
|
127
|
-
instance.class.callbacks.execute(:after_create, instance)
|
128
|
-
end
|
129
|
-
|
130
|
-
return result
|
131
|
-
rescue => error
|
132
|
-
@database.log.error(error)
|
133
|
-
raise error
|
43
|
+
def all(klass, options = {})
|
44
|
+
@adapter.load(self, klass, options)
|
134
45
|
end
|
135
46
|
|
136
|
-
def
|
137
|
-
|
138
|
-
result = @database.execute(@database.update_statement(instance))
|
139
|
-
calculate_original_hashes(instance)
|
140
|
-
instance.class.callbacks.execute(:after_update, instance)
|
141
|
-
return result
|
142
|
-
rescue => error
|
143
|
-
@database.log.error(error)
|
144
|
-
raise error
|
47
|
+
def save(instance)
|
48
|
+
@adapter.save(self, instance)
|
145
49
|
end
|
146
50
|
|
147
51
|
def destroy(instance)
|
148
|
-
|
149
|
-
result = @database.execute(@database.delete_statement(instance))
|
150
|
-
if result.success?
|
151
|
-
instance.instance_variable_set(:@new_record, true)
|
152
|
-
instance.original_hashes.clear
|
153
|
-
instance.class.callbacks.execute(:after_destroy, instance)
|
154
|
-
end
|
155
|
-
return result.success?
|
156
|
-
rescue => error
|
157
|
-
@database.log.error(error)
|
158
|
-
raise error
|
52
|
+
@adapter.delete(instance, :session => self)
|
159
53
|
end
|
160
54
|
|
161
55
|
def delete_all(klass)
|
162
|
-
@
|
56
|
+
@adapter.delete(klass, :session => self)
|
163
57
|
end
|
164
58
|
|
165
59
|
def truncate(klass)
|
166
|
-
@
|
167
|
-
db.execute(@database.truncate_table_statement(klass))
|
168
|
-
end
|
60
|
+
@adapter.delete(klass, :truncate => true, :session => self)
|
169
61
|
end
|
170
62
|
|
171
63
|
def create_table(klass)
|
172
|
-
@
|
173
|
-
db.execute(@database.create_table_statement(klass))
|
174
|
-
end unless table_exists?(klass)
|
64
|
+
@adapter[klass].create!
|
175
65
|
end
|
176
66
|
|
177
67
|
def drop_table(klass)
|
178
|
-
@
|
179
|
-
db.execute(@database.drop_table_statement(klass))
|
180
|
-
end if table_exists?(klass)
|
68
|
+
@adapter[klass].drop!
|
181
69
|
end
|
182
70
|
|
183
71
|
def table_exists?(klass)
|
184
|
-
|
185
|
-
db.query(@database.table_exists_statement(klass))
|
186
|
-
end
|
187
|
-
result = !reader.eof?
|
188
|
-
reader.close
|
189
|
-
result
|
72
|
+
@adapter[klass].exists?
|
190
73
|
end
|
191
74
|
|
192
|
-
def query(*args)
|
193
|
-
|
194
|
-
|
195
|
-
unless args.empty?
|
196
|
-
sql.gsub!(/\?/) do |x|
|
197
|
-
@database.quote_value(args.shift)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
reader = @database.connection do |db|
|
202
|
-
db.query(sql)
|
203
|
-
end
|
204
|
-
|
205
|
-
columns = reader.columns.keys
|
206
|
-
klass = Struct.new(*columns.map { |c| c.to_sym })
|
207
|
-
|
208
|
-
rows = reader.map do |row|
|
209
|
-
klass.new(*columns.map { |c| row[c] })
|
210
|
-
end
|
211
|
-
|
212
|
-
reader.close
|
213
|
-
return rows
|
75
|
+
def query(*args)
|
76
|
+
@adapter.query(*args)
|
214
77
|
end
|
215
78
|
|
216
79
|
def schema
|
217
|
-
@
|
80
|
+
@adapter.schema
|
218
81
|
end
|
219
82
|
|
220
83
|
def log
|
221
|
-
@
|
222
|
-
end
|
223
|
-
|
224
|
-
private
|
225
|
-
|
226
|
-
# Make sure this uses the factory changes later...
|
227
|
-
def type_cast_value(klass, name, raw_value)
|
228
|
-
@database[klass][name].type_cast_value(raw_value)
|
229
|
-
end
|
230
|
-
|
231
|
-
# Calculates the original hashes for each value
|
232
|
-
# in an instance's set of attributes, and adds
|
233
|
-
# them to the original_hashes hash.
|
234
|
-
def calculate_original_hashes(instance)
|
235
|
-
instance.attributes.each_pair do |name, value|
|
236
|
-
instance.original_hashes[name] = value.hash
|
237
|
-
end
|
84
|
+
@adapter.log
|
238
85
|
end
|
86
|
+
|
239
87
|
end
|
240
88
|
end
|