datamapper 0.1.0
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 +2 -0
- data/MIT-LICENSE +22 -0
- data/README +1 -0
- data/example.rb +25 -0
- data/lib/data_mapper.rb +30 -0
- data/lib/data_mapper/adapters/abstract_adapter.rb +229 -0
- data/lib/data_mapper/adapters/mysql_adapter.rb +171 -0
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +189 -0
- data/lib/data_mapper/associations.rb +19 -0
- data/lib/data_mapper/associations/belongs_to_association.rb +111 -0
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +100 -0
- data/lib/data_mapper/associations/has_many_association.rb +101 -0
- data/lib/data_mapper/associations/has_one_association.rb +107 -0
- data/lib/data_mapper/base.rb +160 -0
- data/lib/data_mapper/callbacks.rb +47 -0
- data/lib/data_mapper/database.rb +134 -0
- data/lib/data_mapper/extensions/active_record_impersonation.rb +69 -0
- data/lib/data_mapper/extensions/callback_helpers.rb +35 -0
- data/lib/data_mapper/identity_map.rb +21 -0
- data/lib/data_mapper/loaded_set.rb +45 -0
- data/lib/data_mapper/mappings/column.rb +78 -0
- data/lib/data_mapper/mappings/schema.rb +28 -0
- data/lib/data_mapper/mappings/table.rb +99 -0
- data/lib/data_mapper/queries/conditions.rb +141 -0
- data/lib/data_mapper/queries/connection.rb +34 -0
- data/lib/data_mapper/queries/create_table_statement.rb +38 -0
- data/lib/data_mapper/queries/delete_statement.rb +17 -0
- data/lib/data_mapper/queries/drop_table_statement.rb +17 -0
- data/lib/data_mapper/queries/insert_statement.rb +29 -0
- data/lib/data_mapper/queries/reader.rb +42 -0
- data/lib/data_mapper/queries/result.rb +19 -0
- data/lib/data_mapper/queries/select_statement.rb +103 -0
- data/lib/data_mapper/queries/table_exists_statement.rb +17 -0
- data/lib/data_mapper/queries/truncate_table_statement.rb +17 -0
- data/lib/data_mapper/queries/update_statement.rb +25 -0
- data/lib/data_mapper/session.rb +240 -0
- data/lib/data_mapper/support/blank_slate.rb +3 -0
- data/lib/data_mapper/support/connection_pool.rb +117 -0
- data/lib/data_mapper/support/enumerable.rb +27 -0
- data/lib/data_mapper/support/inflector.rb +329 -0
- data/lib/data_mapper/support/proc.rb +69 -0
- data/lib/data_mapper/support/string.rb +23 -0
- data/lib/data_mapper/support/symbol.rb +91 -0
- data/lib/data_mapper/support/weak_hash.rb +46 -0
- data/lib/data_mapper/unit_of_work.rb +38 -0
- data/lib/data_mapper/validations/confirmation_validator.rb +55 -0
- data/lib/data_mapper/validations/contextual_validations.rb +50 -0
- data/lib/data_mapper/validations/format_validator.rb +85 -0
- data/lib/data_mapper/validations/formats/email.rb +78 -0
- data/lib/data_mapper/validations/generic_validator.rb +27 -0
- data/lib/data_mapper/validations/length_validator.rb +75 -0
- data/lib/data_mapper/validations/required_field_validator.rb +47 -0
- data/lib/data_mapper/validations/unique_validator.rb +65 -0
- data/lib/data_mapper/validations/validation_errors.rb +34 -0
- data/lib/data_mapper/validations/validation_helper.rb +60 -0
- data/performance.rb +156 -0
- data/profile_data_mapper.rb +18 -0
- data/rakefile.rb +80 -0
- data/spec/basic_finder.rb +67 -0
- data/spec/belongs_to.rb +47 -0
- data/spec/fixtures/animals.yaml +32 -0
- data/spec/fixtures/exhibits.yaml +90 -0
- data/spec/fixtures/fruit.yaml +6 -0
- data/spec/fixtures/people.yaml +15 -0
- data/spec/fixtures/zoos.yaml +20 -0
- data/spec/has_and_belongs_to_many.rb +25 -0
- data/spec/has_many.rb +34 -0
- data/spec/legacy.rb +14 -0
- data/spec/models/animal.rb +7 -0
- data/spec/models/exhibit.rb +6 -0
- data/spec/models/fruit.rb +6 -0
- data/spec/models/person.rb +7 -0
- data/spec/models/post.rb +4 -0
- data/spec/models/sales_person.rb +4 -0
- data/spec/models/zoo.rb +5 -0
- data/spec/new_record.rb +24 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/sub_select.rb +16 -0
- data/spec/symbolic_operators.rb +21 -0
- data/spec/validates_confirmation_of.rb +36 -0
- data/spec/validates_format_of.rb +61 -0
- data/spec/validates_length_of.rb +101 -0
- data/spec/validates_uniqueness_of.rb +45 -0
- data/spec/validations.rb +63 -0
- metadata +134 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/result'
|
2
|
+
require File.dirname(__FILE__) + '/reader'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
module Queries
|
6
|
+
|
7
|
+
class Connection
|
8
|
+
|
9
|
+
def initialize(logger)
|
10
|
+
@logger = logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def log
|
14
|
+
@logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute(sql)
|
18
|
+
raise NotImplementedError.new
|
19
|
+
Results.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def query(sql)
|
23
|
+
raise NotImplementedError.new
|
24
|
+
Reader.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def close
|
28
|
+
raise NotImplementedError.new
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end # module Queries
|
34
|
+
end # module DataMapper
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Queries
|
3
|
+
|
4
|
+
class CreateTableStatement
|
5
|
+
|
6
|
+
def initialize(database, klass)
|
7
|
+
@database, @klass = database, klass
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_sql
|
11
|
+
table = @database[@klass]
|
12
|
+
|
13
|
+
sql = "CREATE TABLE " << table.to_sql << " ("
|
14
|
+
|
15
|
+
sql << table.columns.map do |column|
|
16
|
+
column_long_form(column)
|
17
|
+
end.join(', ')
|
18
|
+
|
19
|
+
sql << ", PRIMARY KEY (#{table.key.to_sql}))"
|
20
|
+
|
21
|
+
return sql
|
22
|
+
end
|
23
|
+
|
24
|
+
def column_long_form(column)
|
25
|
+
long_form = "#{column.to_sql} #{@database.adapter.class::TYPES[column.type] || column.type}"
|
26
|
+
|
27
|
+
long_form << "(#{column.size})" unless column.size.nil?
|
28
|
+
long_form << " NOT NULL" unless column.nullable?
|
29
|
+
long_form << " " << @database.syntax(:auto_increment) if column.key?
|
30
|
+
long_form << " default #{column.options[:default]}" if column.options.has_key?(:default)
|
31
|
+
|
32
|
+
return long_form
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Queries
|
3
|
+
|
4
|
+
class DeleteStatement
|
5
|
+
|
6
|
+
def initialize(database, instance)
|
7
|
+
@database, @instance = database, instance
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_sql
|
11
|
+
"DELETE FROM " << @database[@instance.class].to_sql << " WHERE id = " << @database.quote_value(@instance.key)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Queries
|
3
|
+
|
4
|
+
class InsertStatement
|
5
|
+
|
6
|
+
def initialize(database, instance)
|
7
|
+
@database, @instance = database, instance
|
8
|
+
end
|
9
|
+
|
10
|
+
# The only thing this method is responsible for is generating the insert statement.
|
11
|
+
# It is the database adapters responsibility to get the last inserted id
|
12
|
+
def to_sql
|
13
|
+
|
14
|
+
table = @database[@instance.class]
|
15
|
+
|
16
|
+
keys = []
|
17
|
+
values = []
|
18
|
+
|
19
|
+
@instance.dirty_attributes.each_pair { |k,v| keys << table[k].to_sql; values << v }
|
20
|
+
|
21
|
+
# Formatting is a bit off here, but it looks nicer in the log this way.
|
22
|
+
sql = "INSERT INTO #{table.to_sql} (#{keys.join(', ')}) \
|
23
|
+
VALUES (#{values.map { |v| @database.quote_value(v) }.join(', ')})"
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Queries
|
3
|
+
|
4
|
+
class Reader
|
5
|
+
|
6
|
+
attr_reader :columns
|
7
|
+
|
8
|
+
def initialize(database_result_set)
|
9
|
+
end
|
10
|
+
|
11
|
+
def eof?
|
12
|
+
raise NotImplementedError.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def records_affected
|
16
|
+
raise NotImplementedError.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def each
|
20
|
+
raise NotImplementedError.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def entries
|
24
|
+
raise NotImplementedError.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](column)
|
28
|
+
raise NotImplementedError.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def each_pair
|
32
|
+
raise NotImplementedError.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def close
|
36
|
+
raise NotImplementedError.new
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end # module Queries
|
42
|
+
end # module DataMapper
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Queries
|
3
|
+
|
4
|
+
class Result
|
5
|
+
|
6
|
+
attr_accessor :size, :last_inserted_id
|
7
|
+
|
8
|
+
def initialize(size, last_inserted_id = nil)
|
9
|
+
@size, @last_inserted_id = size, last_inserted_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def success?
|
13
|
+
size > 0
|
14
|
+
end
|
15
|
+
|
16
|
+
end # class Result
|
17
|
+
|
18
|
+
end # module Queries
|
19
|
+
end # module DataMapper
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'data_mapper/queries/conditions'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Queries
|
5
|
+
|
6
|
+
class SelectStatement
|
7
|
+
|
8
|
+
def initialize(database, options)
|
9
|
+
@database, @options = database, options
|
10
|
+
end
|
11
|
+
|
12
|
+
def limit
|
13
|
+
@options[:limit]
|
14
|
+
end
|
15
|
+
|
16
|
+
def order
|
17
|
+
@options[:order]
|
18
|
+
end
|
19
|
+
|
20
|
+
def klass
|
21
|
+
@options[:class]
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_id?
|
25
|
+
conditions.has_id?
|
26
|
+
end
|
27
|
+
|
28
|
+
def escape(conditions)
|
29
|
+
@database.escape(conditions)
|
30
|
+
end
|
31
|
+
|
32
|
+
def inspect
|
33
|
+
@options.inspect
|
34
|
+
end
|
35
|
+
|
36
|
+
def include?(association_name)
|
37
|
+
return false if includes.empty?
|
38
|
+
includes.include?(association_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def includes
|
42
|
+
list = @options[:include] ||= []
|
43
|
+
list.kind_of?(Array) ? list : [list]
|
44
|
+
end
|
45
|
+
|
46
|
+
def reload?
|
47
|
+
@options[:reload]
|
48
|
+
end
|
49
|
+
|
50
|
+
def select
|
51
|
+
select_columns = @options[:select]
|
52
|
+
unless select_columns.nil?
|
53
|
+
select_columns = select_columns.kind_of?(Array) ? select_columns : (@options[:select] = [select_columns])
|
54
|
+
select_columns.map { |column| @database.quote_column_name(column.to_s) }
|
55
|
+
else
|
56
|
+
@options[:select] = @database[klass].columns.select do |column|
|
57
|
+
include?(column.name) || !column.lazy?
|
58
|
+
end.map { |column| column.to_sql }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def instance_id
|
63
|
+
@options[:id]
|
64
|
+
end
|
65
|
+
|
66
|
+
def conditions
|
67
|
+
@conditions ||= Conditions.new(@database, @options)
|
68
|
+
end
|
69
|
+
|
70
|
+
def table
|
71
|
+
@table_name || @table_name = if @options.has_key?(:table)
|
72
|
+
@database.quote_table_name(@options[:table])
|
73
|
+
else
|
74
|
+
@database[klass].to_sql
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_sql
|
79
|
+
sql = 'SELECT ' << select.join(', ') << ' FROM ' << table
|
80
|
+
|
81
|
+
where = []
|
82
|
+
|
83
|
+
where += conditions.to_a unless conditions.empty?
|
84
|
+
|
85
|
+
unless where.empty?
|
86
|
+
sql << ' WHERE (' << where.join(') AND (') << ')'
|
87
|
+
end
|
88
|
+
|
89
|
+
unless order.nil?
|
90
|
+
sql << ' ORDER BY ' << order.to_s
|
91
|
+
end
|
92
|
+
|
93
|
+
unless limit.nil?
|
94
|
+
sql << ' LIMIT ' << limit.to_s
|
95
|
+
end
|
96
|
+
|
97
|
+
return sql
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Queries
|
3
|
+
|
4
|
+
class TableExistsStatement
|
5
|
+
|
6
|
+
def initialize(database, klass)
|
7
|
+
@database, @klass = database, klass
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_sql
|
11
|
+
"SHOW TABLES LIKE #{@database.quote_value(@database[@klass].name)}"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Queries
|
3
|
+
|
4
|
+
class UpdateStatement
|
5
|
+
|
6
|
+
def initialize(database, instance)
|
7
|
+
@database, @instance = database, instance
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_sql
|
11
|
+
table = @database[@instance.class]
|
12
|
+
|
13
|
+
sql = "UPDATE " << table.to_sql << " SET "
|
14
|
+
|
15
|
+
@instance.dirty_attributes.map do |k, v|
|
16
|
+
sql << table[k].to_sql << " = " << @database.quote_value(v) << ", "
|
17
|
+
end
|
18
|
+
|
19
|
+
sql[0, sql.size - 2] << " WHERE #{table.key.to_sql} = " << @database.quote_value(@instance.key)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'data_mapper/loaded_set'
|
2
|
+
require 'data_mapper/identity_map'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
|
6
|
+
class Session
|
7
|
+
|
8
|
+
FIND_OPTIONS = [
|
9
|
+
:select, :limit, :class, :include, :reload, :conditions, :order
|
10
|
+
]
|
11
|
+
|
12
|
+
class MaterializationError < StandardError
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(database)
|
16
|
+
@database = database
|
17
|
+
end
|
18
|
+
|
19
|
+
def identity_map
|
20
|
+
@identity_map || ( @identity_map = IdentityMap.new )
|
21
|
+
end
|
22
|
+
|
23
|
+
def find(klass, type_or_id, options = {}, &b)
|
24
|
+
options.merge! b.to_hash if block_given?
|
25
|
+
|
26
|
+
results = case type_or_id
|
27
|
+
when :first then
|
28
|
+
first(@database.select_statement(options.merge(:class => klass, :limit => 1)))
|
29
|
+
when :all then
|
30
|
+
all(@database.select_statement(options.merge(:class => klass)))
|
31
|
+
else
|
32
|
+
first(@database.select_statement(options.merge(:class => klass, :id => type_or_id)))
|
33
|
+
end
|
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'])
|
74
|
+
else
|
75
|
+
options.klass
|
76
|
+
end
|
77
|
+
|
78
|
+
mapping = @database[instance_class]
|
79
|
+
|
80
|
+
instance_id = mapping.key.type_cast_value(hash['id'])
|
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?
|
116
|
+
end
|
117
|
+
|
118
|
+
def insert(instance, inserted_id = nil)
|
119
|
+
instance.class.callbacks.execute(:before_create, instance)
|
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
|
134
|
+
end
|
135
|
+
|
136
|
+
def update(instance)
|
137
|
+
instance.class.callbacks.execute(:before_update, instance)
|
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
|
145
|
+
end
|
146
|
+
|
147
|
+
def destroy(instance)
|
148
|
+
instance.class.callbacks.execute(:before_destroy, instance)
|
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
|
159
|
+
end
|
160
|
+
|
161
|
+
def delete_all(klass)
|
162
|
+
@database.execute(@database.delete_statement(klass))
|
163
|
+
end
|
164
|
+
|
165
|
+
def truncate(klass)
|
166
|
+
@database.connection do |db|
|
167
|
+
db.execute(@database.truncate_table_statement(klass))
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def create_table(klass)
|
172
|
+
@database.connection do |db|
|
173
|
+
db.execute(@database.create_table_statement(klass))
|
174
|
+
end unless table_exists?(klass)
|
175
|
+
end
|
176
|
+
|
177
|
+
def drop_table(klass)
|
178
|
+
@database.connection do |db|
|
179
|
+
db.execute(@database.drop_table_statement(klass))
|
180
|
+
end if table_exists?(klass)
|
181
|
+
end
|
182
|
+
|
183
|
+
def table_exists?(klass)
|
184
|
+
reader = @database.connection do |db|
|
185
|
+
db.query(@database.table_exists_statement(klass))
|
186
|
+
end
|
187
|
+
result = !reader.eof?
|
188
|
+
reader.close
|
189
|
+
result
|
190
|
+
end
|
191
|
+
|
192
|
+
def query(*args)
|
193
|
+
sql = args.shift
|
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
|
214
|
+
end
|
215
|
+
|
216
|
+
def schema
|
217
|
+
@database.schema
|
218
|
+
end
|
219
|
+
|
220
|
+
def log
|
221
|
+
@database.log
|
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
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|