rpbertp13-dm-core 0.9.11.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/.autotest +26 -0
- data/.gitignore +18 -0
- data/CONTRIBUTING +51 -0
- data/FAQ +92 -0
- data/History.txt +52 -0
- data/MIT-LICENSE +22 -0
- data/Manifest.txt +130 -0
- data/QUICKLINKS +11 -0
- data/README.txt +143 -0
- data/Rakefile +32 -0
- data/SPECS +62 -0
- data/TODO +1 -0
- data/dm-core.gemspec +40 -0
- data/lib/dm-core.rb +217 -0
- data/lib/dm-core/adapters.rb +16 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +209 -0
- data/lib/dm-core/adapters/data_objects_adapter.rb +716 -0
- data/lib/dm-core/adapters/in_memory_adapter.rb +87 -0
- data/lib/dm-core/adapters/mysql_adapter.rb +138 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +189 -0
- data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
- data/lib/dm-core/associations.rb +207 -0
- data/lib/dm-core/associations/many_to_many.rb +147 -0
- data/lib/dm-core/associations/many_to_one.rb +107 -0
- data/lib/dm-core/associations/one_to_many.rb +315 -0
- data/lib/dm-core/associations/one_to_one.rb +61 -0
- data/lib/dm-core/associations/relationship.rb +221 -0
- data/lib/dm-core/associations/relationship_chain.rb +81 -0
- data/lib/dm-core/auto_migrations.rb +105 -0
- data/lib/dm-core/collection.rb +670 -0
- data/lib/dm-core/dependency_queue.rb +32 -0
- data/lib/dm-core/hook.rb +11 -0
- data/lib/dm-core/identity_map.rb +42 -0
- data/lib/dm-core/is.rb +16 -0
- data/lib/dm-core/logger.rb +232 -0
- data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
- data/lib/dm-core/migrator.rb +29 -0
- data/lib/dm-core/model.rb +526 -0
- data/lib/dm-core/naming_conventions.rb +84 -0
- data/lib/dm-core/property.rb +676 -0
- data/lib/dm-core/property_set.rb +169 -0
- data/lib/dm-core/query.rb +676 -0
- data/lib/dm-core/repository.rb +167 -0
- data/lib/dm-core/resource.rb +671 -0
- data/lib/dm-core/scope.rb +58 -0
- data/lib/dm-core/support.rb +7 -0
- data/lib/dm-core/support/array.rb +13 -0
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/errors.rb +23 -0
- data/lib/dm-core/support/kernel.rb +11 -0
- data/lib/dm-core/support/symbol.rb +41 -0
- data/lib/dm-core/transaction.rb +252 -0
- data/lib/dm-core/type.rb +160 -0
- data/lib/dm-core/type_map.rb +80 -0
- data/lib/dm-core/types.rb +19 -0
- data/lib/dm-core/types/boolean.rb +7 -0
- data/lib/dm-core/types/discriminator.rb +34 -0
- data/lib/dm-core/types/object.rb +24 -0
- data/lib/dm-core/types/paranoid_boolean.rb +34 -0
- data/lib/dm-core/types/paranoid_datetime.rb +33 -0
- data/lib/dm-core/types/serial.rb +9 -0
- data/lib/dm-core/types/text.rb +10 -0
- data/lib/dm-core/version.rb +3 -0
- data/script/all +4 -0
- data/script/performance.rb +282 -0
- data/script/profile.rb +87 -0
- data/spec/integration/association_spec.rb +1382 -0
- data/spec/integration/association_through_spec.rb +203 -0
- data/spec/integration/associations/many_to_many_spec.rb +449 -0
- data/spec/integration/associations/many_to_one_spec.rb +163 -0
- data/spec/integration/associations/one_to_many_spec.rb +188 -0
- data/spec/integration/auto_migrations_spec.rb +413 -0
- data/spec/integration/collection_spec.rb +1073 -0
- data/spec/integration/data_objects_adapter_spec.rb +32 -0
- data/spec/integration/dependency_queue_spec.rb +46 -0
- data/spec/integration/model_spec.rb +197 -0
- data/spec/integration/mysql_adapter_spec.rb +85 -0
- data/spec/integration/postgres_adapter_spec.rb +731 -0
- data/spec/integration/property_spec.rb +253 -0
- data/spec/integration/query_spec.rb +514 -0
- data/spec/integration/repository_spec.rb +61 -0
- data/spec/integration/resource_spec.rb +513 -0
- data/spec/integration/sqlite3_adapter_spec.rb +352 -0
- data/spec/integration/sti_spec.rb +273 -0
- data/spec/integration/strategic_eager_loading_spec.rb +156 -0
- data/spec/integration/transaction_spec.rb +60 -0
- data/spec/integration/type_spec.rb +275 -0
- data/spec/lib/logging_helper.rb +18 -0
- data/spec/lib/mock_adapter.rb +27 -0
- data/spec/lib/model_loader.rb +100 -0
- data/spec/lib/publicize_methods.rb +28 -0
- data/spec/models/content.rb +16 -0
- data/spec/models/vehicles.rb +34 -0
- data/spec/models/zoo.rb +48 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
- data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
- data/spec/unit/adapters/data_objects_adapter_spec.rb +632 -0
- data/spec/unit/adapters/in_memory_adapter_spec.rb +98 -0
- data/spec/unit/adapters/postgres_adapter_spec.rb +133 -0
- data/spec/unit/associations/many_to_many_spec.rb +32 -0
- data/spec/unit/associations/many_to_one_spec.rb +159 -0
- data/spec/unit/associations/one_to_many_spec.rb +393 -0
- data/spec/unit/associations/one_to_one_spec.rb +7 -0
- data/spec/unit/associations/relationship_spec.rb +71 -0
- data/spec/unit/associations_spec.rb +242 -0
- data/spec/unit/auto_migrations_spec.rb +111 -0
- data/spec/unit/collection_spec.rb +182 -0
- data/spec/unit/data_mapper_spec.rb +35 -0
- data/spec/unit/identity_map_spec.rb +126 -0
- data/spec/unit/is_spec.rb +80 -0
- data/spec/unit/migrator_spec.rb +33 -0
- data/spec/unit/model_spec.rb +321 -0
- data/spec/unit/naming_conventions_spec.rb +36 -0
- data/spec/unit/property_set_spec.rb +90 -0
- data/spec/unit/property_spec.rb +753 -0
- data/spec/unit/query_spec.rb +571 -0
- data/spec/unit/repository_spec.rb +93 -0
- data/spec/unit/resource_spec.rb +649 -0
- data/spec/unit/scope_spec.rb +142 -0
- data/spec/unit/transaction_spec.rb +469 -0
- data/spec/unit/type_map_spec.rb +114 -0
- data/spec/unit/type_spec.rb +119 -0
- data/tasks/ci.rb +36 -0
- data/tasks/dm.rb +63 -0
- data/tasks/doc.rb +20 -0
- data/tasks/gemspec.rb +23 -0
- data/tasks/hoe.rb +46 -0
- data/tasks/install.rb +20 -0
- metadata +215 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Adapters
|
3
|
+
class InMemoryAdapter < AbstractAdapter
|
4
|
+
def initialize(name, uri_or_options)
|
5
|
+
@records = Hash.new { |hash,model| hash[model] = Array.new }
|
6
|
+
end
|
7
|
+
|
8
|
+
def create(resources)
|
9
|
+
resources.each do |resource|
|
10
|
+
@records[resource.model] << resource
|
11
|
+
end.size # just return the number of records
|
12
|
+
end
|
13
|
+
|
14
|
+
def update(attributes, query)
|
15
|
+
read_many(query).each do |resource|
|
16
|
+
attributes.each do |property,value|
|
17
|
+
property.set!(resource, value)
|
18
|
+
end
|
19
|
+
end.size
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_one(query)
|
23
|
+
read(query, query.model, false)
|
24
|
+
end
|
25
|
+
|
26
|
+
def read_many(query)
|
27
|
+
Collection.new(query) do |set|
|
28
|
+
read(query, set, true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete(query)
|
33
|
+
records = @records[query.model]
|
34
|
+
|
35
|
+
read_many(query).each do |resource|
|
36
|
+
records.delete(resource)
|
37
|
+
end.size
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def read(query, set, many = true)
|
43
|
+
model = query.model
|
44
|
+
conditions = query.conditions
|
45
|
+
|
46
|
+
match_with = many ? :select : :detect
|
47
|
+
|
48
|
+
# Iterate over the records for this model, and return
|
49
|
+
# the ones that match the conditions
|
50
|
+
result = @records[model].send(match_with) do |resource|
|
51
|
+
conditions.all? do |tuple|
|
52
|
+
operator, property, bind_value = *tuple
|
53
|
+
|
54
|
+
value = property.get!(resource)
|
55
|
+
|
56
|
+
case operator
|
57
|
+
when :eql, :in then equality_comparison(bind_value, value)
|
58
|
+
when :not then !equality_comparison(bind_value, value)
|
59
|
+
when :like then Regexp.new(bind_value) =~ value
|
60
|
+
when :gt then !value.nil? && value > bind_value
|
61
|
+
when :gte then !value.nil? && value >= bind_value
|
62
|
+
when :lt then !value.nil? && value < bind_value
|
63
|
+
when :lte then !value.nil? && value <= bind_value
|
64
|
+
else raise "Invalid query operator: #{operator.inspect}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return result unless many
|
70
|
+
|
71
|
+
# TODO Sort
|
72
|
+
|
73
|
+
# TODO Limit
|
74
|
+
|
75
|
+
set.replace(result)
|
76
|
+
end
|
77
|
+
|
78
|
+
def equality_comparison(bind_value, value)
|
79
|
+
case bind_value
|
80
|
+
when Array, Range then bind_value.include?(value)
|
81
|
+
when NilClass then value.nil?
|
82
|
+
else bind_value == value
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
gem 'do_mysql', '~>0.10.0'
|
2
|
+
require 'do_mysql'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
module Adapters
|
6
|
+
# Options:
|
7
|
+
# host, user, password, database (path), socket(uri query string), port
|
8
|
+
class MysqlAdapter < DataObjectsAdapter
|
9
|
+
module SQL
|
10
|
+
private
|
11
|
+
|
12
|
+
def supports_default_values?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def quote_table_name(table_name)
|
17
|
+
"`#{table_name.gsub('`', '``')}`"
|
18
|
+
end
|
19
|
+
|
20
|
+
def quote_column_name(column_name)
|
21
|
+
"`#{column_name.gsub('`', '``')}`"
|
22
|
+
end
|
23
|
+
|
24
|
+
def quote_column_value(column_value)
|
25
|
+
case column_value
|
26
|
+
when TrueClass then quote_column_value(1)
|
27
|
+
when FalseClass then quote_column_value(0)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end #module SQL
|
33
|
+
|
34
|
+
include SQL
|
35
|
+
|
36
|
+
# TODO: move to dm-more/dm-migrations
|
37
|
+
module Migration
|
38
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
39
|
+
def storage_exists?(storage_name)
|
40
|
+
statement = <<-EOS.compress_lines
|
41
|
+
SELECT COUNT(*)
|
42
|
+
FROM `information_schema`.`tables`
|
43
|
+
WHERE `table_type` = 'BASE TABLE'
|
44
|
+
AND `table_schema` = ?
|
45
|
+
AND `table_name` = ?
|
46
|
+
EOS
|
47
|
+
|
48
|
+
query(statement, db_name, storage_name).first > 0
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
52
|
+
def field_exists?(storage_name, field_name)
|
53
|
+
statement = <<-EOS.compress_lines
|
54
|
+
SELECT COUNT(*)
|
55
|
+
FROM `information_schema`.`columns`
|
56
|
+
WHERE `table_schema` = ?
|
57
|
+
AND `table_name` = ?
|
58
|
+
AND `column_name` = ?
|
59
|
+
EOS
|
60
|
+
|
61
|
+
query(statement, db_name, storage_name, field_name).first > 0
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
67
|
+
def db_name
|
68
|
+
@uri.path.split('/').last
|
69
|
+
end
|
70
|
+
|
71
|
+
module SQL
|
72
|
+
private
|
73
|
+
|
74
|
+
# TODO: move to dm-more/dm-migrations
|
75
|
+
def supports_serial?
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
# TODO: move to dm-more/dm-migrations
|
80
|
+
def create_table_statement(repository, model)
|
81
|
+
"#{super} ENGINE = InnoDB CHARACTER SET #{character_set} COLLATE #{collation}"
|
82
|
+
end
|
83
|
+
|
84
|
+
# TODO: move to dm-more/dm-migrations
|
85
|
+
def property_schema_hash(property, model)
|
86
|
+
schema = super
|
87
|
+
schema.delete(:default) if schema[:primitive] == 'TEXT'
|
88
|
+
schema
|
89
|
+
end
|
90
|
+
|
91
|
+
# TODO: move to dm-more/dm-migrations
|
92
|
+
def property_schema_statement(schema)
|
93
|
+
statement = super
|
94
|
+
statement << ' AUTO_INCREMENT' if supports_serial? && schema[:serial?]
|
95
|
+
statement
|
96
|
+
end
|
97
|
+
|
98
|
+
# TODO: move to dm-more/dm-migrations
|
99
|
+
def character_set
|
100
|
+
@character_set ||= show_variable('character_set_connection') || 'utf8'
|
101
|
+
end
|
102
|
+
|
103
|
+
# TODO: move to dm-more/dm-migrations
|
104
|
+
def collation
|
105
|
+
@collation ||= show_variable('collation_connection') || 'utf8_general_ci'
|
106
|
+
end
|
107
|
+
|
108
|
+
# TODO: move to dm-more/dm-migrations
|
109
|
+
def show_variable(name)
|
110
|
+
query('SHOW VARIABLES WHERE `variable_name` = ?', name).first.value rescue nil
|
111
|
+
end
|
112
|
+
end # module SQL
|
113
|
+
|
114
|
+
include SQL
|
115
|
+
|
116
|
+
module ClassMethods
|
117
|
+
# TypeMap for MySql databases.
|
118
|
+
#
|
119
|
+
# @return <DataMapper::TypeMap> default TypeMap for MySql databases.
|
120
|
+
#
|
121
|
+
# TODO: move to dm-more/dm-migrations
|
122
|
+
def type_map
|
123
|
+
@type_map ||= TypeMap.new(super) do |tm|
|
124
|
+
tm.map(Integer).to('INT').with(:size => 11)
|
125
|
+
tm.map(TrueClass).to('TINYINT').with(:size => 1) # TODO: map this to a BIT or CHAR(0) field?
|
126
|
+
tm.map(Object).to('TEXT')
|
127
|
+
tm.map(DateTime).to('DATETIME')
|
128
|
+
tm.map(Time).to('DATETIME')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end # module ClassMethods
|
132
|
+
end # module Migration
|
133
|
+
|
134
|
+
include Migration
|
135
|
+
extend Migration::ClassMethods
|
136
|
+
end # class MysqlAdapter
|
137
|
+
end # module Adapters
|
138
|
+
end # module DataMapper
|
@@ -0,0 +1,189 @@
|
|
1
|
+
gem 'do_postgres', '~>0.10.0'
|
2
|
+
require 'do_postgres'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
module Adapters
|
6
|
+
class PostgresAdapter < DataObjectsAdapter
|
7
|
+
module SQL
|
8
|
+
private
|
9
|
+
|
10
|
+
def supports_returning?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end #module SQL
|
14
|
+
|
15
|
+
include SQL
|
16
|
+
|
17
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
18
|
+
module Migration
|
19
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
20
|
+
def storage_exists?(storage_name)
|
21
|
+
statement = <<-SQL.compress_lines
|
22
|
+
SELECT COUNT(*)
|
23
|
+
FROM "information_schema"."tables"
|
24
|
+
WHERE "table_type" = 'BASE TABLE'
|
25
|
+
AND "table_schema" = current_schema()
|
26
|
+
AND "table_name" = ?
|
27
|
+
SQL
|
28
|
+
|
29
|
+
query(statement, storage_name).first > 0
|
30
|
+
end
|
31
|
+
|
32
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
33
|
+
def field_exists?(storage_name, column_name)
|
34
|
+
statement = <<-SQL.compress_lines
|
35
|
+
SELECT COUNT(*)
|
36
|
+
FROM "information_schema"."columns"
|
37
|
+
WHERE "table_schema" = current_schema()
|
38
|
+
AND "table_name" = ?
|
39
|
+
AND "column_name" = ?
|
40
|
+
SQL
|
41
|
+
|
42
|
+
query(statement, storage_name, column_name).first > 0
|
43
|
+
end
|
44
|
+
|
45
|
+
# TODO: move to dm-more/dm-migrations
|
46
|
+
def upgrade_model_storage(repository, model)
|
47
|
+
add_sequences(repository, model)
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO: move to dm-more/dm-migrations
|
52
|
+
def create_model_storage(repository, model)
|
53
|
+
add_sequences(repository, model)
|
54
|
+
without_notices { super }
|
55
|
+
end
|
56
|
+
|
57
|
+
# TODO: move to dm-more/dm-migrations
|
58
|
+
def destroy_model_storage(repository, model)
|
59
|
+
return true unless storage_exists?(model.storage_name(repository.name))
|
60
|
+
success = without_notices { super }
|
61
|
+
model.properties(repository.name).each do |property|
|
62
|
+
drop_sequence(repository, property) if property.serial?
|
63
|
+
end
|
64
|
+
success
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
# TODO: move to dm-more/dm-migrations
|
70
|
+
def create_sequence(repository, property)
|
71
|
+
return if sequence_exists?(repository, property)
|
72
|
+
execute(create_sequence_statement(repository, property))
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO: move to dm-more/dm-migrations
|
76
|
+
def drop_sequence(repository, property)
|
77
|
+
without_notices { execute(drop_sequence_statement(repository, property)) }
|
78
|
+
end
|
79
|
+
|
80
|
+
module SQL
|
81
|
+
private
|
82
|
+
|
83
|
+
# TODO: move to dm-more/dm-migrations
|
84
|
+
def drop_table_statement(repository, model)
|
85
|
+
"DROP TABLE #{quote_table_name(model.storage_name(repository.name))}"
|
86
|
+
end
|
87
|
+
|
88
|
+
# TODO: move to dm-more/dm-migrations
|
89
|
+
def without_notices
|
90
|
+
# execute the block with NOTICE messages disabled
|
91
|
+
begin
|
92
|
+
execute('SET client_min_messages = warning')
|
93
|
+
yield
|
94
|
+
ensure
|
95
|
+
execute('RESET client_min_messages')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# TODO: move to dm-more/dm-migrations
|
100
|
+
def add_sequences(repository, model)
|
101
|
+
model.properties(repository.name).each do |property|
|
102
|
+
create_sequence(repository, property) if property.serial?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# TODO: move to dm-more/dm-migrations
|
107
|
+
def sequence_name(repository, property)
|
108
|
+
"#{property.model.storage_name(repository.name)}_#{property.field(repository.name)}_seq"
|
109
|
+
end
|
110
|
+
|
111
|
+
# TODO: move to dm-more/dm-migrations
|
112
|
+
def sequence_exists?(repository, property)
|
113
|
+
statement = <<-EOS.compress_lines
|
114
|
+
SELECT COUNT(*)
|
115
|
+
FROM "information_schema"."sequences"
|
116
|
+
WHERE "sequence_name" = ?
|
117
|
+
AND "sequence_schema" = current_schema()
|
118
|
+
EOS
|
119
|
+
|
120
|
+
query(statement, sequence_name(repository, property)).first > 0
|
121
|
+
end
|
122
|
+
|
123
|
+
# TODO: move to dm-more/dm-migrations
|
124
|
+
def create_sequence_statement(repository, property)
|
125
|
+
"CREATE SEQUENCE #{quote_column_name(sequence_name(repository, property))}"
|
126
|
+
end
|
127
|
+
|
128
|
+
# TODO: move to dm-more/dm-migrations
|
129
|
+
def drop_sequence_statement(repository, property)
|
130
|
+
"DROP SEQUENCE IF EXISTS #{quote_column_name(sequence_name(repository, property))}"
|
131
|
+
end
|
132
|
+
|
133
|
+
# TODO: move to dm-more/dm-migrations
|
134
|
+
def property_schema_statement(schema)
|
135
|
+
statement = super
|
136
|
+
|
137
|
+
if schema.has_key?(:sequence_name)
|
138
|
+
statement << " DEFAULT nextval('#{schema[:sequence_name]}') NOT NULL"
|
139
|
+
end
|
140
|
+
|
141
|
+
statement
|
142
|
+
end
|
143
|
+
|
144
|
+
# TODO: move to dm-more/dm-migrations
|
145
|
+
def property_schema_hash(repository, property)
|
146
|
+
schema = super
|
147
|
+
|
148
|
+
if property.serial?
|
149
|
+
schema.delete(:default) # the sequence will be the default
|
150
|
+
schema[:sequence_name] = sequence_name(repository, property)
|
151
|
+
end
|
152
|
+
|
153
|
+
# TODO: see if TypeMap can be updated to set specific attributes to nil
|
154
|
+
# for different adapters. precision/scale are perfect examples for
|
155
|
+
# Postgres floats
|
156
|
+
|
157
|
+
# Postgres does not support precision and scale for Float
|
158
|
+
if property.primitive == Float
|
159
|
+
schema.delete(:precision)
|
160
|
+
schema.delete(:scale)
|
161
|
+
end
|
162
|
+
|
163
|
+
schema
|
164
|
+
end
|
165
|
+
end # module SQL
|
166
|
+
|
167
|
+
include SQL
|
168
|
+
|
169
|
+
module ClassMethods
|
170
|
+
# TypeMap for PostgreSQL databases.
|
171
|
+
#
|
172
|
+
# @return <DataMapper::TypeMap> default TypeMap for PostgreSQL databases.
|
173
|
+
#
|
174
|
+
# TODO: move to dm-more/dm-migrations
|
175
|
+
def type_map
|
176
|
+
@type_map ||= TypeMap.new(super) do |tm|
|
177
|
+
tm.map(Integer).to('INTEGER')
|
178
|
+
tm.map(BigDecimal).to('NUMERIC').with(:precision => Property::DEFAULT_PRECISION, :scale => Property::DEFAULT_SCALE_BIGDECIMAL)
|
179
|
+
tm.map(Float).to('DOUBLE PRECISION')
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end # module ClassMethods
|
183
|
+
end # module Migration
|
184
|
+
|
185
|
+
include Migration
|
186
|
+
extend Migration::ClassMethods
|
187
|
+
end # class PostgresAdapter
|
188
|
+
end # module Adapters
|
189
|
+
end # module DataMapper
|
@@ -0,0 +1,105 @@
|
|
1
|
+
gem 'do_sqlite3', '~>0.10.0'
|
2
|
+
require 'do_sqlite3'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
module Adapters
|
6
|
+
class Sqlite3Adapter < DataObjectsAdapter
|
7
|
+
module SQL
|
8
|
+
private
|
9
|
+
|
10
|
+
def quote_column_value(column_value)
|
11
|
+
case column_value
|
12
|
+
when TrueClass then quote_column_value('t')
|
13
|
+
when FalseClass then quote_column_value('f')
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end # module SQL
|
19
|
+
|
20
|
+
include SQL
|
21
|
+
|
22
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
23
|
+
module Migration
|
24
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
25
|
+
def storage_exists?(storage_name)
|
26
|
+
query_table(storage_name).size > 0
|
27
|
+
end
|
28
|
+
|
29
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
30
|
+
def field_exists?(storage_name, column_name)
|
31
|
+
query_table(storage_name).any? do |row|
|
32
|
+
row.name == column_name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# TODO: move to dm-more/dm-migrations (if possible)
|
39
|
+
def query_table(table_name)
|
40
|
+
query('PRAGMA table_info(?)', table_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
module SQL
|
44
|
+
# private ## This cannot be private for current migrations
|
45
|
+
|
46
|
+
# TODO: move to dm-more/dm-migrations
|
47
|
+
def supports_serial?
|
48
|
+
sqlite_version >= '3.1.0'
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO: move to dm-more/dm-migrations
|
52
|
+
def create_table_statement(repository, model)
|
53
|
+
statement = <<-EOS.compress_lines
|
54
|
+
CREATE TABLE #{quote_table_name(model.storage_name(repository.name))}
|
55
|
+
(#{model.properties_with_subclasses(repository.name).map { |p| property_schema_statement(property_schema_hash(repository, p)) } * ', '}
|
56
|
+
EOS
|
57
|
+
|
58
|
+
# skip adding the primary key if one of the columns is serial. In
|
59
|
+
# SQLite the serial column must be the primary key, so it has already
|
60
|
+
# been defined
|
61
|
+
unless model.properties(repository.name).any? { |p| p.serial? }
|
62
|
+
if (key = model.properties(repository.name).key).any?
|
63
|
+
statement << ", PRIMARY KEY(#{key.map { |p| quote_column_name(p.field(repository.name)) } * ', '})"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
statement << ')'
|
68
|
+
statement
|
69
|
+
end
|
70
|
+
|
71
|
+
# TODO: move to dm-more/dm-migrations
|
72
|
+
def property_schema_statement(schema)
|
73
|
+
statement = super
|
74
|
+
statement << ' PRIMARY KEY AUTOINCREMENT' if supports_serial? && schema[:serial?]
|
75
|
+
statement
|
76
|
+
end
|
77
|
+
|
78
|
+
# TODO: move to dm-more/dm-migrations
|
79
|
+
def sqlite_version
|
80
|
+
@sqlite_version ||= query('SELECT sqlite_version(*)').first
|
81
|
+
end
|
82
|
+
end # module SQL
|
83
|
+
|
84
|
+
include SQL
|
85
|
+
|
86
|
+
module ClassMethods
|
87
|
+
# TypeMap for SQLite 3 databases.
|
88
|
+
#
|
89
|
+
# @return <DataMapper::TypeMap> default TypeMap for SQLite 3 databases.
|
90
|
+
#
|
91
|
+
# TODO: move to dm-more/dm-migrations
|
92
|
+
def type_map
|
93
|
+
@type_map ||= TypeMap.new(super) do |tm|
|
94
|
+
tm.map(Integer).to('INTEGER')
|
95
|
+
tm.map(Class).to('VARCHAR')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end # module ClassMethods
|
99
|
+
end # module Migration
|
100
|
+
|
101
|
+
include Migration
|
102
|
+
extend Migration::ClassMethods
|
103
|
+
end # class Sqlite3Adapter
|
104
|
+
end # module Adapters
|
105
|
+
end # module DataMapper
|