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