datamapper 0.1.1 → 0.2.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 +65 -0
- data/README +193 -1
- data/do_performance.rb +153 -0
- data/environment.rb +45 -0
- data/example.rb +119 -22
- data/lib/data_mapper.rb +36 -16
- data/lib/data_mapper/adapters/abstract_adapter.rb +8 -0
- data/lib/data_mapper/adapters/data_object_adapter.rb +360 -0
- data/lib/data_mapper/adapters/mysql_adapter.rb +30 -179
- data/lib/data_mapper/adapters/postgresql_adapter.rb +90 -199
- data/lib/data_mapper/adapters/sql/coersion.rb +32 -3
- data/lib/data_mapper/adapters/sql/commands/conditions.rb +97 -128
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +234 -231
- data/lib/data_mapper/adapters/sql/commands/loader.rb +99 -0
- data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +30 -0
- data/lib/data_mapper/adapters/sql/mappings/column.rb +68 -6
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +6 -3
- data/lib/data_mapper/adapters/sql/mappings/table.rb +71 -42
- data/lib/data_mapper/adapters/sql/quoting.rb +8 -2
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +32 -201
- data/lib/data_mapper/associations.rb +21 -7
- data/lib/data_mapper/associations/belongs_to_association.rb +96 -80
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +158 -67
- data/lib/data_mapper/associations/has_many_association.rb +96 -78
- data/lib/data_mapper/associations/has_n_association.rb +64 -0
- data/lib/data_mapper/associations/has_one_association.rb +49 -79
- data/lib/data_mapper/associations/reference.rb +47 -0
- data/lib/data_mapper/base.rb +216 -50
- data/lib/data_mapper/callbacks.rb +71 -24
- data/lib/data_mapper/{session.rb → context.rb} +20 -8
- data/lib/data_mapper/database.rb +176 -45
- data/lib/data_mapper/embedded_value.rb +65 -0
- data/lib/data_mapper/identity_map.rb +12 -4
- data/lib/data_mapper/support/active_record_impersonation.rb +12 -8
- data/lib/data_mapper/support/enumerable.rb +8 -0
- data/lib/data_mapper/support/serialization.rb +13 -0
- data/lib/data_mapper/support/string.rb +1 -12
- data/lib/data_mapper/support/symbol.rb +3 -0
- data/lib/data_mapper/validations/unique_validator.rb +1 -2
- data/lib/data_mapper/validations/validation_helper.rb +18 -1
- data/performance.rb +109 -34
- data/plugins/can_has_sphinx/LICENSE +23 -0
- data/plugins/can_has_sphinx/README +4 -0
- data/plugins/can_has_sphinx/REVISION +1 -0
- data/plugins/can_has_sphinx/Rakefile +22 -0
- data/plugins/can_has_sphinx/init.rb +1 -0
- data/plugins/can_has_sphinx/install.rb +1 -0
- data/plugins/can_has_sphinx/lib/acts_as_sphinx.rb +123 -0
- data/plugins/can_has_sphinx/lib/sphinx.rb +460 -0
- data/plugins/can_has_sphinx/scripts/sphinx.sh +47 -0
- data/plugins/can_has_sphinx/tasks/acts_as_sphinx_tasks.rake +41 -0
- data/plugins/dataobjects/REVISION +1 -0
- data/plugins/dataobjects/Rakefile +7 -0
- data/plugins/dataobjects/do.rb +246 -0
- data/plugins/dataobjects/do_mysql.rb +179 -0
- data/plugins/dataobjects/do_postgres.rb +181 -0
- data/plugins/dataobjects/do_sqlite3.rb +153 -0
- data/plugins/dataobjects/spec/do_spec.rb +150 -0
- data/plugins/dataobjects/spec/spec_helper.rb +81 -0
- data/plugins/dataobjects/swig_mysql/do_mysql.bundle +0 -0
- data/plugins/dataobjects/swig_mysql/extconf.rb +33 -0
- data/plugins/dataobjects/swig_mysql/mysql_c.c +18800 -0
- data/plugins/dataobjects/swig_mysql/mysql_c.i +8 -0
- data/plugins/dataobjects/swig_mysql/mysql_supp.i +46 -0
- data/plugins/dataobjects/swig_postgres/Makefile +146 -0
- data/plugins/dataobjects/swig_postgres/extconf.rb +29 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.bundle +0 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.c +8185 -0
- data/plugins/dataobjects/swig_postgres/postgres_c.i +73 -0
- data/plugins/dataobjects/swig_sqlite/db +0 -0
- data/plugins/dataobjects/swig_sqlite/extconf.rb +9 -0
- data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +4725 -0
- data/plugins/dataobjects/swig_sqlite/sqlite_c.i +168 -0
- data/rakefile.rb +45 -23
- data/spec/acts_as_tree_spec.rb +39 -0
- data/spec/associations_spec.rb +220 -0
- data/spec/attributes_spec.rb +15 -0
- data/spec/base_spec.rb +44 -0
- data/spec/callbacks_spec.rb +45 -0
- data/spec/can_has_sphinx.rb +6 -0
- data/spec/coersion_spec.rb +34 -0
- data/spec/conditions_spec.rb +49 -0
- data/spec/conversions_to_yaml_spec.rb +17 -0
- data/spec/count_command_spec.rb +11 -0
- data/spec/delete_command_spec.rb +1 -1
- data/spec/embedded_value_spec.rb +23 -0
- data/spec/fixtures/animals_exhibits.yaml +2 -0
- data/spec/fixtures/people.yaml +18 -1
- data/spec/{legacy.rb → legacy_spec.rb} +3 -3
- data/spec/load_command_spec.rb +157 -20
- data/spec/magic_columns_spec.rb +9 -0
- data/spec/mock_adapter.rb +20 -0
- data/spec/models/animal.rb +1 -1
- data/spec/models/animals_exhibit.rb +6 -0
- data/spec/models/exhibit.rb +2 -0
- data/spec/models/person.rb +26 -1
- data/spec/models/project.rb +19 -0
- data/spec/models/sales_person.rb +1 -0
- data/spec/models/section.rb +6 -0
- data/spec/models/zoo.rb +3 -1
- data/spec/query_spec.rb +9 -0
- data/spec/save_command_spec.rb +65 -1
- data/spec/schema_spec.rb +89 -0
- data/spec/single_table_inheritance_spec.rb +27 -0
- data/spec/spec_helper.rb +9 -55
- data/spec/{symbolic_operators.rb → symbolic_operators_spec.rb} +9 -5
- data/spec/{validates_confirmation_of.rb → validates_confirmation_of_spec.rb} +4 -3
- data/spec/{validates_format_of.rb → validates_format_of_spec.rb} +5 -4
- data/spec/{validates_length_of.rb → validates_length_of_spec.rb} +8 -7
- data/spec/{validates_uniqueness_of.rb → validates_uniqueness_of_spec.rb} +7 -10
- data/spec/{validations.rb → validations_spec.rb} +24 -6
- data/tasks/drivers.rb +20 -0
- data/tasks/fixtures.rb +42 -0
- metadata +181 -42
- data/lib/data_mapper/adapters/sql/commands/advanced_load_command.rb +0 -140
- data/lib/data_mapper/adapters/sql/commands/delete_command.rb +0 -113
- data/lib/data_mapper/adapters/sql/commands/save_command.rb +0 -141
- data/lib/data_mapper/adapters/sql/commands/table_exists_command.rb +0 -33
- data/lib/data_mapper/adapters/sql_adapter.rb +0 -163
- data/lib/data_mapper/associations/advanced_has_many_association.rb +0 -55
- data/lib/data_mapper/support/blank_slate.rb +0 -3
- data/lib/data_mapper/support/proc.rb +0 -69
- data/lib/data_mapper/support/struct.rb +0 -26
- data/lib/data_mapper/unit_of_work.rb +0 -38
- data/spec/basic_finder.rb +0 -67
- data/spec/belongs_to.rb +0 -47
- data/spec/has_and_belongs_to_many.rb +0 -25
- data/spec/has_many.rb +0 -34
- data/spec/new_record.rb +0 -24
- data/spec/sub_select.rb +0 -16
- data/spec/support/string_spec.rb +0 -7
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
module DataMapper
|
|
2
|
-
module Adapters
|
|
3
|
-
module Sql
|
|
4
|
-
module Commands
|
|
5
|
-
|
|
6
|
-
class AdvancedLoadCommand
|
|
7
|
-
|
|
8
|
-
attr_reader :conditions, :options
|
|
9
|
-
|
|
10
|
-
def initialize(adapter, session, primary_class, options = {})
|
|
11
|
-
@adapter, @session, @primary_class, @options = adapter, session, primary_class, options
|
|
12
|
-
|
|
13
|
-
@order = @options[:order]
|
|
14
|
-
@limit = @options[:limit]
|
|
15
|
-
@offset = @options[:offset]
|
|
16
|
-
@reload = @options[:reload]
|
|
17
|
-
@include = @options[:include]
|
|
18
|
-
@instance_id = @options[:id]
|
|
19
|
-
@conditions = @options[:conditions]
|
|
20
|
-
@join_fetch = false
|
|
21
|
-
@joins = []
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# If +true+ then force the command to reload any objects
|
|
25
|
-
# already existing in the IdentityMap when executing.
|
|
26
|
-
def reload?
|
|
27
|
-
@reload
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Determine if there is a limitation on the number of
|
|
31
|
-
# instances returned in the results. If +nil+, no limit
|
|
32
|
-
# is set. Can be used in conjunction with #offset for
|
|
33
|
-
# paging through a set of results.
|
|
34
|
-
def limit
|
|
35
|
-
@limit
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Used in conjunction with #limit to page through a set
|
|
39
|
-
# of results.
|
|
40
|
-
def offset
|
|
41
|
-
@offset
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Generate a select statement based on the initialization
|
|
45
|
-
# arguments.
|
|
46
|
-
def to_sql
|
|
47
|
-
sql = 'SELECT ' << columns_for_select.join(', ')
|
|
48
|
-
sql << ' FROM ' << from_table_name
|
|
49
|
-
|
|
50
|
-
if @join_fetch
|
|
51
|
-
@joins.each do |entry|
|
|
52
|
-
primary_table, association_table, association = entry
|
|
53
|
-
sql << ' JOIN ' << association_table.to_sql << ' ON '
|
|
54
|
-
sql << association_table.to_sql << '.'
|
|
55
|
-
sql << @adapter.quote_column_name(association.foreign_key)
|
|
56
|
-
sql << ' = ' << primary_table.key.to_sql(true)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
return sql
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
# Return the Sql-escaped columns names to be selected in the results.
|
|
66
|
-
def columns_for_select
|
|
67
|
-
@columns_for_select || @columns_for_select = begin
|
|
68
|
-
columns.map { |column| column.to_sql(@join_fetch) }
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Returns the DataMapper::Adapters::Sql::Mappings::Column instances to
|
|
73
|
-
# be selected in the results.
|
|
74
|
-
def columns
|
|
75
|
-
@columns || begin
|
|
76
|
-
@columns = if @options.has_key?(:select)
|
|
77
|
-
primary_class_table.columns.select do |column|
|
|
78
|
-
@options[:select].include?(column.name)
|
|
79
|
-
end
|
|
80
|
-
else
|
|
81
|
-
primary_class_table.columns.select do |column|
|
|
82
|
-
include_column?(column.name) || !column.lazy?
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Return if there is no +:include+ option to evaluate.
|
|
87
|
-
return @columns if @include.nil?
|
|
88
|
-
|
|
89
|
-
if @include.kind_of?(Array)
|
|
90
|
-
# Return if all +:include+ parameters are columns in
|
|
91
|
-
# the primary_class_table.
|
|
92
|
-
return @columns if @include.all? do |name|
|
|
93
|
-
!primary_class_table[name].nil?
|
|
94
|
-
end
|
|
95
|
-
elsif @include.kind_of?(Symbol)
|
|
96
|
-
# Return if the include is a column in the primary_class_table.
|
|
97
|
-
return @columns if primary_class_table[@include]
|
|
98
|
-
|
|
99
|
-
primary_class_table.associations.each do |association|
|
|
100
|
-
next unless association.name == @include
|
|
101
|
-
association_table = @adapter[association.constant]
|
|
102
|
-
@columns += association_table.columns
|
|
103
|
-
@joins << [ primary_class_table, association_table, association ]
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
@join_fetch = true
|
|
107
|
-
else
|
|
108
|
-
raise ':include option must be a Symbol or Array of Symbols'
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
@columns
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Determine if a Column should be included based on the
|
|
116
|
-
# value of the +:include+ option.
|
|
117
|
-
def include_column?(name)
|
|
118
|
-
case @include
|
|
119
|
-
when nil then false
|
|
120
|
-
when Symbol then @include == name
|
|
121
|
-
when Array then @include.includes?(name)
|
|
122
|
-
else raise ':include option must be a Symbol or Array of Symbols'
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Return the Sql-escaped table name of the +primary_class+.
|
|
127
|
-
def from_table_name
|
|
128
|
-
@from_table_name || (@from_table_name = @adapter[@primary_class].to_sql)
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# Returns the DataMapper::Adapters::Sql::Mappings::Table for the +primary_class+.
|
|
132
|
-
def primary_class_table
|
|
133
|
-
@primary_class_table || (@primary_class_table = @adapter[@primary_class])
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
end # class LoadCommand
|
|
137
|
-
end # module Commands
|
|
138
|
-
end # module Sql
|
|
139
|
-
end # module Adapters
|
|
140
|
-
end # module DataMapper
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
module DataMapper
|
|
2
|
-
module Adapters
|
|
3
|
-
module Sql
|
|
4
|
-
module Commands
|
|
5
|
-
|
|
6
|
-
class DeleteCommand
|
|
7
|
-
|
|
8
|
-
def initialize(adapter, klass_or_instance, options = nil)
|
|
9
|
-
@adapter, @klass_or_instance, @options = adapter, klass_or_instance, options
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def truncate?
|
|
13
|
-
return false if @options.nil?
|
|
14
|
-
@options[:truncate]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def drop?
|
|
18
|
-
return false if @options.nil?
|
|
19
|
-
@options[:drop]
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def delete_all?
|
|
23
|
-
return !truncate? && !drop? && @klass_or_instance.kind_of?(Class)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def klass
|
|
27
|
-
@klass_or_instance.kind_of?(Class) ? @klass_or_instance : @klass_or_instance.class
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def to_truncate_sql
|
|
31
|
-
"TRUNCATE TABLE " << @adapter[@klass_or_instance].to_sql
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def to_drop_sql
|
|
35
|
-
"DROP TABLE #{@adapter[@klass_or_instance].to_sql}"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def to_delete_sql
|
|
39
|
-
sql = "DELETE FROM " << @adapter[klass].to_sql
|
|
40
|
-
sql << " WHERE id = " << @adapter.quote_value(@klass_or_instance.key) unless delete_all?
|
|
41
|
-
return sql
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def to_sql
|
|
45
|
-
if truncate?
|
|
46
|
-
to_truncate_sql
|
|
47
|
-
elsif drop?
|
|
48
|
-
to_drop_sql
|
|
49
|
-
else
|
|
50
|
-
to_delete_sql
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def session
|
|
55
|
-
return nil if @options.nil?
|
|
56
|
-
@options[:session]
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def call
|
|
60
|
-
result = nil
|
|
61
|
-
|
|
62
|
-
if truncate?
|
|
63
|
-
result = execute_truncate(to_sql)
|
|
64
|
-
session.identity_map.clear!(klass) unless session.nil?
|
|
65
|
-
elsif drop?
|
|
66
|
-
result = execute_drop(to_sql)
|
|
67
|
-
session.identity_map.clear!(klass) unless session.nil?
|
|
68
|
-
elsif delete_all?
|
|
69
|
-
result = execute_delete_all(to_sql)
|
|
70
|
-
session.identity_map.clear!(klass) unless session.nil?
|
|
71
|
-
else
|
|
72
|
-
@klass_or_instance.class.callbacks.execute(:before_destroy, @klass_or_instance)
|
|
73
|
-
|
|
74
|
-
result = execute(to_sql)
|
|
75
|
-
|
|
76
|
-
if result
|
|
77
|
-
@klass_or_instance.instance_variable_set(:@new_record, true)
|
|
78
|
-
@klass_or_instance.session = session
|
|
79
|
-
@klass_or_instance.original_hashes.clear
|
|
80
|
-
session.identity_map.delete(@klass_or_instance) unless session.nil?
|
|
81
|
-
@klass_or_instance.class.callbacks.execute(:after_destroy, @klass_or_instance)
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
return result
|
|
86
|
-
rescue => error
|
|
87
|
-
@adapter.log.error(error)
|
|
88
|
-
raise error
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
protected
|
|
92
|
-
def execute_truncate(sql)
|
|
93
|
-
execute(sql)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def execute_drop(sql)
|
|
97
|
-
execute(sql)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def execute_delete_all(sql)
|
|
101
|
-
execute(sql)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def execute(sql)
|
|
105
|
-
raise NotImplementedError.new
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
module DataMapper
|
|
2
|
-
module Adapters
|
|
3
|
-
module Sql
|
|
4
|
-
module Commands
|
|
5
|
-
|
|
6
|
-
class SaveCommand
|
|
7
|
-
|
|
8
|
-
def initialize(adapter, session, instance)
|
|
9
|
-
@adapter, @session, @instance = adapter, session, instance
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def to_update_sql
|
|
13
|
-
table = @adapter[@instance.class]
|
|
14
|
-
|
|
15
|
-
sql = "UPDATE " << table.to_sql << " SET "
|
|
16
|
-
|
|
17
|
-
@instance.dirty_attributes.map do |k, v|
|
|
18
|
-
sql << table[k].to_sql << " = " << @adapter.quote_value(v) << ", "
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
sql[0, sql.size - 2] << " WHERE #{table.key.to_sql} = " << @adapter.quote_value(@instance.key)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def to_insert_sql
|
|
25
|
-
|
|
26
|
-
table = @adapter[@instance.class]
|
|
27
|
-
|
|
28
|
-
keys = []
|
|
29
|
-
values = []
|
|
30
|
-
|
|
31
|
-
@instance.dirty_attributes.each_pair { |k,v| keys << table[k].to_sql; values << v }
|
|
32
|
-
|
|
33
|
-
# Formatting is a bit off here, but it looks nicer in the log this way.
|
|
34
|
-
sql = "INSERT INTO #{table.to_sql} (#{keys.join(', ')}) \
|
|
35
|
-
VALUES (#{values.map { |v| @adapter.quote_value(v) }.join(', ')})"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def to_create_table_sql
|
|
39
|
-
table = @adapter[@instance]
|
|
40
|
-
|
|
41
|
-
sql = "CREATE TABLE " << table.to_sql << " ("
|
|
42
|
-
|
|
43
|
-
sql << table.columns.map do |column|
|
|
44
|
-
column_long_form(column)
|
|
45
|
-
end.join(', ')
|
|
46
|
-
|
|
47
|
-
sql << ", PRIMARY KEY (#{table.key.to_sql}))"
|
|
48
|
-
|
|
49
|
-
return sql
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def column_long_form(column)
|
|
53
|
-
long_form = "#{column.to_sql} #{@adapter.class::TYPES[column.type] || column.type}"
|
|
54
|
-
|
|
55
|
-
long_form << "(#{column.size})" unless column.size.nil?
|
|
56
|
-
long_form << " NOT NULL" unless column.nullable?
|
|
57
|
-
long_form << " auto_increment" if column.key?
|
|
58
|
-
long_form << " default #{column.options[:default]}" if column.options.has_key?(:default)
|
|
59
|
-
|
|
60
|
-
return long_form
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def callback(name)
|
|
64
|
-
@instance.class.callbacks.execute(name, @instance)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def insert!
|
|
68
|
-
callback(:before_create)
|
|
69
|
-
|
|
70
|
-
result = execute_insert(to_insert_sql)
|
|
71
|
-
|
|
72
|
-
if result
|
|
73
|
-
@instance.instance_variable_set(:@new_record, false)
|
|
74
|
-
@instance.instance_variable_set(:@id, result)
|
|
75
|
-
calculate_original_hashes(@instance)
|
|
76
|
-
@session.identity_map.set(@instance)
|
|
77
|
-
callback(:after_create)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
return result
|
|
81
|
-
rescue => error
|
|
82
|
-
@adapter.log.error(error)
|
|
83
|
-
raise error
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def update!
|
|
87
|
-
callback(:before_update)
|
|
88
|
-
|
|
89
|
-
result = execute_update(to_update_sql)
|
|
90
|
-
|
|
91
|
-
calculate_original_hashes(@instance)
|
|
92
|
-
callback(:after_update)
|
|
93
|
-
return result
|
|
94
|
-
rescue => error
|
|
95
|
-
@adapter.log.error(error)
|
|
96
|
-
raise error
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def call
|
|
100
|
-
if @instance.kind_of?(Class)
|
|
101
|
-
return false if @adapter.table_exists?(@instance)
|
|
102
|
-
execute_create_table(to_create_table_sql)
|
|
103
|
-
else
|
|
104
|
-
return false unless @instance.dirty?
|
|
105
|
-
callback(:before_save)
|
|
106
|
-
result = @instance.new_record? ? insert! : update!
|
|
107
|
-
@instance.session = @session
|
|
108
|
-
callback(:after_save)
|
|
109
|
-
result
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
protected
|
|
114
|
-
def execute_insert(sql)
|
|
115
|
-
raise NotImplementedError.new
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def execute_update(sql)
|
|
119
|
-
raise NotImplementedError.new
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def execute_create_table(sql)
|
|
123
|
-
raise NotImplementedError.new
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
private
|
|
127
|
-
# Calculates the original hashes for each value
|
|
128
|
-
# in an instance's set of attributes, and adds
|
|
129
|
-
# them to the original_hashes hash.
|
|
130
|
-
def calculate_original_hashes(instance)
|
|
131
|
-
instance.attributes.each_pair do |name, value|
|
|
132
|
-
instance.original_hashes[name] = value.hash
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
module DataMapper
|
|
2
|
-
module Adapters
|
|
3
|
-
module Sql
|
|
4
|
-
module Commands
|
|
5
|
-
|
|
6
|
-
class TableExistsCommand
|
|
7
|
-
|
|
8
|
-
def initialize(adapter, klass_or_name)
|
|
9
|
-
@adapter, @klass_or_name = adapter, klass_or_name
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def table_name
|
|
13
|
-
@table_name || @table_name = case @klass_or_name
|
|
14
|
-
when String then @adapter.quote_value(@klass_or_name)
|
|
15
|
-
when Class then @adapter.quote_value(@adapter[@klass_or_name].name)
|
|
16
|
-
else raise ArgumentError.new('klass_or_name must be a mapped-class or a table name')
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def to_sql
|
|
21
|
-
"SHOW TABLES LIKE #{table_name}"
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def call
|
|
25
|
-
raise NotImplementedError.new
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
require 'data_mapper/adapters/abstract_adapter'
|
|
2
|
-
require 'data_mapper/adapters/sql/commands/load_command'
|
|
3
|
-
require 'data_mapper/adapters/sql/commands/advanced_load_command'
|
|
4
|
-
require 'data_mapper/adapters/sql/commands/save_command'
|
|
5
|
-
require 'data_mapper/adapters/sql/commands/delete_command'
|
|
6
|
-
require 'data_mapper/adapters/sql/commands/table_exists_command'
|
|
7
|
-
require 'data_mapper/adapters/sql/coersion'
|
|
8
|
-
require 'data_mapper/adapters/sql/quoting'
|
|
9
|
-
require 'data_mapper/adapters/sql/mappings/schema'
|
|
10
|
-
|
|
11
|
-
module DataMapper
|
|
12
|
-
|
|
13
|
-
# An Adapter is really a Factory for three types of object,
|
|
14
|
-
# so they can be selectively sub-classed where needed.
|
|
15
|
-
#
|
|
16
|
-
# The first type is a Query. The Query is an object describing
|
|
17
|
-
# the database-specific operations we wish to perform, in an
|
|
18
|
-
# abstract manner. For example: While most if not all databases
|
|
19
|
-
# support a mechanism for limiting the size of results returned,
|
|
20
|
-
# some use a "LIMIT" keyword, while others use a "TOP" keyword.
|
|
21
|
-
# We can set a SelectStatement#limit field then, and allow
|
|
22
|
-
# the adapter to override the underlying SQL generated.
|
|
23
|
-
# Refer to DataMapper::Queries.
|
|
24
|
-
#
|
|
25
|
-
# The second type provided by the Adapter is a DataMapper::Connection.
|
|
26
|
-
# This allows us to execute queries and return results in a clear and
|
|
27
|
-
# uniform manner we can use throughout the DataMapper.
|
|
28
|
-
#
|
|
29
|
-
# The final type provided is a DataMapper::Transaction.
|
|
30
|
-
# Transactions are duck-typed Connections that span multiple queries.
|
|
31
|
-
#
|
|
32
|
-
# Note: It is assumed that the Adapter implements it's own
|
|
33
|
-
# ConnectionPool if any since some libraries implement their own at
|
|
34
|
-
# a low-level, and it wouldn't make sense to pay a performance
|
|
35
|
-
# cost twice by implementing a secondary pool in the DataMapper itself.
|
|
36
|
-
# If the library being adapted does not provide such functionality,
|
|
37
|
-
# DataMapper::Support::ConnectionPool can be used.
|
|
38
|
-
module Adapters
|
|
39
|
-
|
|
40
|
-
# You must inherit from the SqlAdapter, and implement the
|
|
41
|
-
# required methods to adapt a database library for use with the DataMapper.
|
|
42
|
-
#
|
|
43
|
-
# NOTE: By inheriting from SqlAdapter, you get a copy of all the
|
|
44
|
-
# standard sub-modules (Quoting, Coersion and Queries) in your own Adapter.
|
|
45
|
-
# You can extend and overwrite these copies without affecting the originals.
|
|
46
|
-
class SqlAdapter < AbstractAdapter
|
|
47
|
-
|
|
48
|
-
FIND_OPTIONS = [
|
|
49
|
-
:select, :limit, :class, :include, :reload, :conditions, :order
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
def initialize(configuration)
|
|
53
|
-
super
|
|
54
|
-
@single_threaded = configuration.single_threaded
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def single_threaded?
|
|
58
|
-
@single_threaded
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def connection(&block)
|
|
62
|
-
raise NotImplementedError.new
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def transaction(&block)
|
|
66
|
-
raise NotImplementedError.new
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def query(sql)
|
|
70
|
-
raise NotImplementedError.new
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def schema
|
|
74
|
-
@schema || ( @schema = Mappings::Schema.new(self) )
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def table_exists?(name)
|
|
78
|
-
self.class::Commands::TableExistsCommand.new(self, name).call
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def delete(klass_or_instance, options = nil)
|
|
82
|
-
self.class::Commands::DeleteCommand.new(self, klass_or_instance, options).call
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def save(session, instance)
|
|
86
|
-
self.class::Commands::SaveCommand.new(self, session, instance).call
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def load(session, klass, options)
|
|
90
|
-
self.class::Commands::LoadCommand.new(self, session, klass, options).call
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def [](klass_or_table_name)
|
|
94
|
-
schema[klass_or_table_name]
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Escape a string of SQL with a set of arguments.
|
|
98
|
-
# The first argument is assumed to be the SQL to escape,
|
|
99
|
-
# the remaining arguments (if any) are assumed to be
|
|
100
|
-
# values to escape and interpolate.
|
|
101
|
-
#
|
|
102
|
-
# ==== Examples
|
|
103
|
-
# escape_sql("SELECT * FROM zoos")
|
|
104
|
-
# # => "SELECT * FROM zoos"
|
|
105
|
-
#
|
|
106
|
-
# escape_sql("SELECT * FROM zoos WHERE name = ?", "Dallas")
|
|
107
|
-
# # => "SELECT * FROM zoos WHERE name = `Dallas`"
|
|
108
|
-
#
|
|
109
|
-
# escape_sql("SELECT * FROM zoos WHERE name = ? AND acreage > ?", "Dallas", 40)
|
|
110
|
-
# # => "SELECT * FROM zoos WHERE name = `Dallas` AND acreage > 40"
|
|
111
|
-
#
|
|
112
|
-
# ==== Warning
|
|
113
|
-
# This method is meant mostly for adapters that don't support
|
|
114
|
-
# bind-parameters.
|
|
115
|
-
def escape_sql(*args)
|
|
116
|
-
sql = args.shift
|
|
117
|
-
|
|
118
|
-
unless args.empty?
|
|
119
|
-
sql.gsub!(/\?/) do |x|
|
|
120
|
-
quote_value(args.shift)
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
sql
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# This callback copies and sub-classes modules and classes
|
|
128
|
-
# in the AbstractAdapter to the inherited class so you don't
|
|
129
|
-
# have to copy and paste large blocks of code from the
|
|
130
|
-
# SqlAdapter.
|
|
131
|
-
#
|
|
132
|
-
# Basically, when inheriting from the AbstractAdapter, you
|
|
133
|
-
# aren't just inheriting a single class, you're inheriting
|
|
134
|
-
# a whole graph of Types. For convenience.
|
|
135
|
-
def self.inherited(base)
|
|
136
|
-
|
|
137
|
-
queries = base.const_set('Commands', Module.new)
|
|
138
|
-
|
|
139
|
-
Sql::Commands.constants.each do |name|
|
|
140
|
-
queries.const_set(name, Class.new(Sql::Commands.const_get(name)))
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
base.const_set('TYPES', TYPES.dup)
|
|
144
|
-
base.const_set('FIND_OPTIONS', FIND_OPTIONS.dup)
|
|
145
|
-
|
|
146
|
-
super
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
TYPES = {
|
|
150
|
-
:integer => 'int'.freeze,
|
|
151
|
-
:string => 'varchar'.freeze,
|
|
152
|
-
:text => 'text'.freeze,
|
|
153
|
-
:class => 'varchar'.freeze
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
include Sql
|
|
157
|
-
include Quoting
|
|
158
|
-
include Coersion
|
|
159
|
-
|
|
160
|
-
end # class SqlAdapter
|
|
161
|
-
|
|
162
|
-
end # module Adapters
|
|
163
|
-
end # module DataMapper
|