whorm 0.4.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/LICENSE +20 -0
- data/README.rdoc +113 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/lib/test/macros.rb +20 -0
- data/lib/whorm.rb +15 -0
- data/lib/whorm/adapters/active_record.rb +88 -0
- data/lib/whorm/adapters/data_mapper.rb +66 -0
- data/lib/whorm/adapters/mongo_mapper.rb +64 -0
- data/lib/whorm/model.rb +370 -0
- data/test/active_record_test.rb +0 -0
- data/test/app/config/application.rb +70 -0
- data/test/app/config/database.yml +3 -0
- data/test/app/db/schema.rb +75 -0
- data/test/app/models/active_record/address.rb +4 -0
- data/test/app/models/active_record/data_type.rb +3 -0
- data/test/app/models/active_record/group.rb +4 -0
- data/test/app/models/active_record/house.rb +4 -0
- data/test/app/models/active_record/location.rb +5 -0
- data/test/app/models/active_record/person.rb +4 -0
- data/test/app/models/active_record/user.rb +6 -0
- data/test/app/models/active_record/user_group.rb +4 -0
- data/test/data_mapper_test.rb +0 -0
- data/test/model_test.rb +526 -0
- data/test/mongo_mapper_test.rb +0 -0
- data/test/test_helper.rb +32 -0
- metadata +123 -0
data/lib/whorm/model.rb
ADDED
@@ -0,0 +1,370 @@
|
|
1
|
+
module Whorm
|
2
|
+
module Model
|
3
|
+
|
4
|
+
def self.included(model)
|
5
|
+
model.send(:extend, ClassMethods)
|
6
|
+
model.send(:include, InstanceMethods)
|
7
|
+
##
|
8
|
+
# @config {String} whorm_parent_trail_template This a template used to render mapped field-names.
|
9
|
+
# Default is Proc.new{ |field_name| "_#{field_name}" }
|
10
|
+
# You could also use the Rails standard
|
11
|
+
# Proc.new{ |field_name| "[#{field_name}]" }
|
12
|
+
#
|
13
|
+
model.cattr_accessor :whorm_parent_trail_template
|
14
|
+
model.whorm_parent_trail_template = Proc.new{ |field_name| "_#{field_name}" } if model.whorm_parent_trail_template.nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# InstanceMethods
|
19
|
+
#
|
20
|
+
module InstanceMethods
|
21
|
+
|
22
|
+
##
|
23
|
+
# Converts a model instance to a record compatible with javascript applications
|
24
|
+
#
|
25
|
+
# The first parameter should be the fieldset for which the record will be returned.
|
26
|
+
# If no parameter is provided, then the default fieldset will be choosen
|
27
|
+
# Alternativly the first parameter can be a Hash with a :fields member to directly specify
|
28
|
+
# the fields to use for the record.
|
29
|
+
#
|
30
|
+
# All these are valid calls:
|
31
|
+
#
|
32
|
+
# user.to_record # returns record for :default fieldset
|
33
|
+
# # (fieldset is autmatically defined, if not set)
|
34
|
+
#
|
35
|
+
# user.to_record :fieldset # returns record for :fieldset fieldset
|
36
|
+
# # (fieldset is autmatically defined, if not set)
|
37
|
+
#
|
38
|
+
# user.to_record :fields => [:id, :password]
|
39
|
+
# # returns record for the fields 'id' and 'password'
|
40
|
+
#
|
41
|
+
# For even more valid options for this method (which all should not be neccessary to use)
|
42
|
+
# have a look at Whorm::Model::Util.extract_fieldset_and_options
|
43
|
+
def to_record(*params)
|
44
|
+
fieldset, options = Util.extract_fieldset_and_options params
|
45
|
+
|
46
|
+
fields = []
|
47
|
+
if options[:fields].empty?
|
48
|
+
fields = self.class.whorm_get_fields_for_fieldset(fieldset)
|
49
|
+
else
|
50
|
+
fields = self.class.process_fields(*options[:fields])
|
51
|
+
end
|
52
|
+
|
53
|
+
assns = self.class.whorm_associations
|
54
|
+
pk = self.class.whorm_primary_key
|
55
|
+
|
56
|
+
# build the initial field data-hash
|
57
|
+
data = {pk => self.send(pk)}
|
58
|
+
|
59
|
+
fields.each do |field|
|
60
|
+
next if data.has_key? field[:name] # already processed (e.g. explicit mentioning of :id)
|
61
|
+
|
62
|
+
value = nil
|
63
|
+
if association_reflection = assns[field[:name]] # if field is an association
|
64
|
+
association = self.send(field[:name])
|
65
|
+
|
66
|
+
# skip this association if we already visited it
|
67
|
+
# otherwise we could end up in a cyclic reference
|
68
|
+
next if options[:visited_classes].include? association.class
|
69
|
+
|
70
|
+
case association_reflection[:type]
|
71
|
+
when :belongs_to, :has_one
|
72
|
+
if association.respond_to? :to_record
|
73
|
+
assn_fields = field[:fields]
|
74
|
+
if assn_fields.nil?
|
75
|
+
assn_fields = association.class.whorm_get_fields_for_fieldset(field.fetch(:fieldset, fieldset))
|
76
|
+
end
|
77
|
+
|
78
|
+
value = association.to_record :fields => assn_fields,
|
79
|
+
:visited_classes => options[:visited_classes] + [self.class]
|
80
|
+
else
|
81
|
+
value = {}
|
82
|
+
(field[:fields]||[]).each do |sub_field|
|
83
|
+
value[sub_field[:name]] = association.send(sub_field[:name]) if association.respond_to? sub_field[:name]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if association_reflection[:type] == :belongs_to
|
87
|
+
# Append associations foreign_key to data
|
88
|
+
data[association_reflection[:foreign_key]] = self.send(association_reflection[:foreign_key])
|
89
|
+
if association_reflection[:is_polymorphic]
|
90
|
+
foreign_type = self.class.whorm_polymorphic_type(association_reflection[:foreign_key])
|
91
|
+
data[foreign_type] = self.send(foreign_type)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
when :many
|
95
|
+
value = association.collect { |r| r.to_record } # use carefully, can get HUGE
|
96
|
+
end
|
97
|
+
else # not an association -> get the method's value
|
98
|
+
value = self.send(field[:name])
|
99
|
+
value = value.to_record if value.respond_to? :to_record
|
100
|
+
end
|
101
|
+
data[field[:name]] = value
|
102
|
+
end
|
103
|
+
data
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# ClassMethods
|
109
|
+
#
|
110
|
+
module ClassMethods
|
111
|
+
##
|
112
|
+
# render AR columns to Ext.data.Record.create format
|
113
|
+
# eg: {name:'foo', type: 'string'}
|
114
|
+
#
|
115
|
+
# The first parameter should be the fieldset for which the record definition will be returned.
|
116
|
+
# If no parameter is provided, then the default fieldset will be choosen
|
117
|
+
# Alternativly the first parameter can be a Hash with a :fields member to directly specify
|
118
|
+
# the fields to use for the record config.
|
119
|
+
#
|
120
|
+
# All these are valid calls:
|
121
|
+
#
|
122
|
+
# User.whorm_schema # returns record config for :default fieldset
|
123
|
+
# # (fieldset is autmatically defined, if not set)
|
124
|
+
#
|
125
|
+
# User.whorm_schema :fieldset # returns record config for :fieldset fieldset
|
126
|
+
# # (fieldset is autmatically defined, if not set)
|
127
|
+
#
|
128
|
+
# User.whorm_schema :fields => [:id, :password]
|
129
|
+
# # returns record config for the fields 'id' and 'password'
|
130
|
+
#
|
131
|
+
# For even more valid options for this method (which all should not be neccessary to use)
|
132
|
+
# have a look at Whorm::Model::Util.extract_fieldset_and_options
|
133
|
+
def whorm_schema(*params)
|
134
|
+
fieldset, options = Util.extract_fieldset_and_options params
|
135
|
+
|
136
|
+
if options[:fields].empty?
|
137
|
+
fields = self.whorm_get_fields_for_fieldset(fieldset)
|
138
|
+
else
|
139
|
+
fields = self.process_fields(*options[:fields])
|
140
|
+
end
|
141
|
+
|
142
|
+
associations = self.whorm_associations
|
143
|
+
columns = self.whorm_columns_hash
|
144
|
+
pk = self.whorm_primary_key
|
145
|
+
rs = []
|
146
|
+
|
147
|
+
fields.each do |field|
|
148
|
+
|
149
|
+
field = Marshal.load(Marshal.dump(field)) # making a deep copy
|
150
|
+
|
151
|
+
if col = columns[field[:name]] # <-- column on this model
|
152
|
+
rs << self.whorm_field(field, col)
|
153
|
+
elsif assn = associations[field[:name]]
|
154
|
+
# skip this association if we already visited it
|
155
|
+
# otherwise we could end up in a cyclic reference
|
156
|
+
next if options[:visited_classes].include? assn[:class]
|
157
|
+
|
158
|
+
assn_fields = field[:fields]
|
159
|
+
if assn[:class].respond_to?(:whorm_schema) # <-- exec whorm_schema on assn Model.
|
160
|
+
if assn_fields.nil?
|
161
|
+
assn_fields = assn[:class].whorm_get_fields_for_fieldset(field.fetch(:fieldset, fieldset))
|
162
|
+
end
|
163
|
+
|
164
|
+
record = assn[:class].whorm_schema(field.fetch(:fieldset, fieldset), { :visited_classes => options[:visited_classes] + [self], :fields => assn_fields})
|
165
|
+
rs.concat(record[:fields].collect { |assn_field|
|
166
|
+
self.whorm_field(assn_field, :parent_trail => field[:name], :mapping => field[:name], :allowBlank => true) # <-- allowBlank on associated data?
|
167
|
+
})
|
168
|
+
elsif assn_fields # <-- :parent => [:id, :name, :sub => [:id, :name]]
|
169
|
+
field_collector = Proc.new do |parent_trail, mapping, assn_field|
|
170
|
+
if assn_field.is_a?(Hash) && assn_field.keys.size == 1 && assn_field.keys[0].is_a?(Symbol) && assn_field.values[0].is_a?(Array)
|
171
|
+
field_collector.call(parent_trail.to_s + self.whorm_parent_trail_template.call(assn_field.keys.first), "#{mapping}.#{assn_field.keys.first}", assn_field.values.first)
|
172
|
+
else
|
173
|
+
self.whorm_field(assn_field, :parent_trail => parent_trail, :mapping => mapping, :allowBlank => true)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
rs.concat(assn_fields.collect { |assn_field| field_collector.call(field[:name], field[:name], assn_field) })
|
177
|
+
else
|
178
|
+
rs << whorm_field(field)
|
179
|
+
end
|
180
|
+
|
181
|
+
# attach association's foreign_key if not already included.
|
182
|
+
if columns.has_key?(assn[:foreign_key]) && !rs.any? { |r| r[:name] == assn[:foreign_key] }
|
183
|
+
rs << whorm_field({:name => assn[:foreign_key]}, columns[assn[:foreign_key]])
|
184
|
+
end
|
185
|
+
# attach association's type if polymorphic association and not alredy included
|
186
|
+
if assn[:is_polymorphic]
|
187
|
+
foreign_type = self.whorm_polymorphic_type(assn[:foreign_key])
|
188
|
+
if columns.has_key?(foreign_type) && !rs.any? { |r| r[:name] == foreign_type }
|
189
|
+
rs << whorm_field({:name => foreign_type}, columns[foreign_type])
|
190
|
+
end
|
191
|
+
end
|
192
|
+
else # property is a method?
|
193
|
+
rs << whorm_field(field)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
return {
|
198
|
+
:fields => rs,
|
199
|
+
:idProperty => pk
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# meant to be used within a Model to define the whorm record fields.
|
205
|
+
# eg:
|
206
|
+
# class User
|
207
|
+
# whorm_fieldset :grid, [:first, :last, :email => {"sortDir" => "ASC"}, :company => [:id, :name]]
|
208
|
+
# end
|
209
|
+
# or
|
210
|
+
# class User
|
211
|
+
# whorm_fieldset :last, :email => {"sortDir" => "ASC"}, :company => [:id, :name] # => implies fieldset name :default
|
212
|
+
# end
|
213
|
+
#
|
214
|
+
def whorm_fieldset(*params)
|
215
|
+
fieldset, options = Util.extract_fieldset_and_options params
|
216
|
+
var_name = :"@whorm_fieldsets__#{fieldset}"
|
217
|
+
self.instance_variable_set( var_name, self.process_fields(*options[:fields]) )
|
218
|
+
end
|
219
|
+
|
220
|
+
def whorm_get_fields_for_fieldset(fieldset)
|
221
|
+
var_name = :"@whorm_fieldsets__#{fieldset}"
|
222
|
+
super_value = nil
|
223
|
+
unless self.instance_variable_get( var_name )
|
224
|
+
if self.superclass.respond_to? :whorm_get_fields_for_fieldset
|
225
|
+
super_value = self.superclass.whorm_get_fields_for_fieldset(fieldset)
|
226
|
+
end
|
227
|
+
self.whorm_fieldset(fieldset, self.whorm_column_names) unless super_value
|
228
|
+
end
|
229
|
+
super_value || self.instance_variable_get( var_name )
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# shortcut to define the default fieldset. For backwards-compatibility.
|
234
|
+
#
|
235
|
+
def whorm_fields(*params)
|
236
|
+
self.whorm_fieldset(:default, {
|
237
|
+
:fields => params
|
238
|
+
})
|
239
|
+
end
|
240
|
+
|
241
|
+
##
|
242
|
+
# Prepare a field configuration list into a normalized array of Hashes, {:name => "field_name"}
|
243
|
+
# @param {Mixed} params
|
244
|
+
# @return {Array} of Hashes
|
245
|
+
#
|
246
|
+
def process_fields(*params)
|
247
|
+
fields = []
|
248
|
+
if params.size == 1 && params.last.is_a?(Hash) # peek into argument to see if its an option hash
|
249
|
+
options = params.last
|
250
|
+
if options.has_key?(:additional) && options[:additional].is_a?(Array)
|
251
|
+
return self.process_fields(*(self.whorm_column_names + options[:additional].map(&:to_sym)))
|
252
|
+
elsif options.has_key?(:exclude) && options[:exclude].is_a?(Array)
|
253
|
+
return self.process_fields(*(self.whorm_column_names - options[:exclude].map(&:to_sym)))
|
254
|
+
elsif options.has_key?(:only) && options[:only].is_a?(Array)
|
255
|
+
return self.process_fields(*options[:only])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
params = self.whorm_column_names if params.empty?
|
260
|
+
|
261
|
+
associations = whorm_associations
|
262
|
+
|
263
|
+
params.each do |f|
|
264
|
+
if f.kind_of?(Hash)
|
265
|
+
if f.keys.size == 1 && f.keys[0].is_a?(Symbol) && f.values[0].is_a?(Array) # {:association => [:field1, :field2]}
|
266
|
+
fields << {
|
267
|
+
:name => f.keys[0],
|
268
|
+
:fields => process_fields(*f.values[0])
|
269
|
+
}
|
270
|
+
elsif f.keys.size == 1 && f.keys[0].is_a?(Symbol) && f.values[0].is_a?(Hash) # {:field => {:sortDir => 'ASC'}}
|
271
|
+
fields << f.values[0].update(:name => f.keys[0])
|
272
|
+
elsif f.has_key?(:name) # already a valid Hash, just copy it over
|
273
|
+
fields << f
|
274
|
+
else
|
275
|
+
raise ArgumentError, "encountered a Hash that I don't know anything to do with `#{f.inspect}:#{f.class}`"
|
276
|
+
end
|
277
|
+
else # should be a String or Symbol
|
278
|
+
raise ArgumentError, "encountered a fields Array that I don't understand: #{params.inspect} -- `#{f.inspect}:#{f.class}` is not a Symbol or String" unless f.is_a?(Symbol) || f.is_a?(String)
|
279
|
+
fields << {:name => f.to_sym}
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
fields
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Render a column-config object
|
288
|
+
# @param {Hash/Column} field Field-configuration Hash, probably has :name already set and possibly Ext.data.Field options.
|
289
|
+
# @param {ORM Column Object from AR, DM or MM}
|
290
|
+
#
|
291
|
+
def whorm_field(field, config=nil)
|
292
|
+
if config.kind_of? Hash
|
293
|
+
if config.has_key?(:mapping) && config.has_key?(:parent_trail)
|
294
|
+
field.update( # <-- We use a template for rendering mapped field-names.
|
295
|
+
:name => config[:parent_trail].to_s + self.whorm_parent_trail_template.call(field[:name]),
|
296
|
+
:mapping => "#{config[:mapping]}.#{field[:name]}"
|
297
|
+
)
|
298
|
+
end
|
299
|
+
field.update(config.except(:mapping, :parent_trail))
|
300
|
+
elsif !config.nil? # <-- Hopfully an ORM Column object.
|
301
|
+
field.update(
|
302
|
+
:allowBlank => self.whorm_allow_blank(config),
|
303
|
+
:type => self.whorm_type(config),
|
304
|
+
:defaultValue => self.whorm_default(config)
|
305
|
+
)
|
306
|
+
field[:dateFormat] = "c" if field[:type] === "date" && field[:dateFormat].nil? # <-- ugly hack for date
|
307
|
+
end
|
308
|
+
field.update(:type => "auto") if field[:type].nil?
|
309
|
+
# convert Symbol values to String values
|
310
|
+
field.keys.each do |k|
|
311
|
+
raise ArgumentError, "whorm_field expects a Hash as first parameter with all it's keys Symbols. Found key #{k.inspect}:#{k.class.to_s}" unless k.is_a?(Symbol)
|
312
|
+
field[k] = field[k].to_s if field[k].is_a?(Symbol)
|
313
|
+
end
|
314
|
+
field
|
315
|
+
end
|
316
|
+
|
317
|
+
# ##
|
318
|
+
# # Returns an array of symbolized association names that will be referenced by a call to to_record
|
319
|
+
# # i.e. [:parent1, :parent2]
|
320
|
+
# #
|
321
|
+
# def whorm_used_associations
|
322
|
+
# if @whorm_used_associations.nil?
|
323
|
+
# assoc = []
|
324
|
+
# self.whorm_record_fields.each do |f|
|
325
|
+
# #This needs to be the first condition because the others will break if f is an Array
|
326
|
+
# if whorm_associations[f[:name]]
|
327
|
+
# assoc << f[:name]
|
328
|
+
# end
|
329
|
+
# end
|
330
|
+
# @whorm_used_associations = assoc.uniq
|
331
|
+
# end
|
332
|
+
# @whorm_used_associations
|
333
|
+
# end
|
334
|
+
end
|
335
|
+
|
336
|
+
module Util
|
337
|
+
|
338
|
+
##
|
339
|
+
# returns the fieldset from the arguments and normalizes the options.
|
340
|
+
# @return [{Symbol}, {Hash}]
|
341
|
+
def self.extract_fieldset_and_options arguments
|
342
|
+
orig_args = arguments
|
343
|
+
fieldset = :default
|
344
|
+
options = { # default options
|
345
|
+
:visited_classes => [],
|
346
|
+
:fields => []
|
347
|
+
}
|
348
|
+
if arguments.size > 2 || (arguments.size == 2 && !arguments[0].is_a?(Symbol))
|
349
|
+
raise ArgumentError, "Don't know how to handle #{arguments.inspect}"
|
350
|
+
elsif arguments.size == 2 && arguments[0].is_a?(Symbol)
|
351
|
+
fieldset = arguments.shift
|
352
|
+
if arguments[0].is_a?(Array)
|
353
|
+
options.update({
|
354
|
+
:fields => arguments[0]
|
355
|
+
})
|
356
|
+
elsif arguments[0].is_a?(Hash)
|
357
|
+
options.update(arguments[0])
|
358
|
+
end
|
359
|
+
elsif arguments.size == 1 && (arguments[0].is_a?(Symbol) || arguments[0].is_a?(String))
|
360
|
+
fieldset = arguments.shift.to_sym
|
361
|
+
elsif arguments.size == 1 && arguments[0].is_a?(Hash)
|
362
|
+
fieldset = arguments[0].delete(:fieldset) || :default
|
363
|
+
options.update(arguments[0])
|
364
|
+
end
|
365
|
+
[fieldset, options]
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
File without changes
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# TODO: Figure out how to iterate each ORM framework AR, DM, MM and test each.
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_support'
|
4
|
+
require 'whorm'
|
5
|
+
require 'extlib/inflection'
|
6
|
+
|
7
|
+
gem 'sqlite3-ruby'
|
8
|
+
|
9
|
+
class Test::App
|
10
|
+
|
11
|
+
attr_reader :models
|
12
|
+
|
13
|
+
def initialize(orm = :active_record)
|
14
|
+
@orm = orm
|
15
|
+
@config = YAML::load(IO.read("#{ROOT}/config/database.yml"))
|
16
|
+
|
17
|
+
# Load ORM
|
18
|
+
send("boot_#{orm.to_s}")
|
19
|
+
|
20
|
+
load_models
|
21
|
+
|
22
|
+
require 'db/schema'
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Reset a model's @whorm_fieldsets
|
28
|
+
#
|
29
|
+
def clean_all
|
30
|
+
@models.map { |klass| clean klass }
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def boot_active_record
|
37
|
+
ActiveRecord::Base.establish_connection(@config['test'])
|
38
|
+
end
|
39
|
+
|
40
|
+
def boot_mongo_mapper
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def boot_data_mapper
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Do a dir on /models and constantize each filename
|
50
|
+
#
|
51
|
+
def load_models
|
52
|
+
@models = []
|
53
|
+
# Load Models and Schema for corresponding orm
|
54
|
+
re = /^.*\/(.*).rb$/
|
55
|
+
Dir["#{ROOT}/models/#{@orm.to_s}/*"].each { |c|
|
56
|
+
require c
|
57
|
+
match = c.match(re)
|
58
|
+
@models << Extlib::Inflection.constantize(Extlib::Inflection.camelize(match[1])) if match
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def clean klass
|
63
|
+
klass.instance_variables.each do |var_name|
|
64
|
+
if /\A@whorm_fieldsets__/ =~ var_name.to_s
|
65
|
+
klass.instance_variable_set( var_name.to_sym, nil )
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
##
|
3
|
+
# build simple database
|
4
|
+
#
|
5
|
+
# people
|
6
|
+
#
|
7
|
+
ActiveRecord::Base.connection.create_table :users, :force => true do |table|
|
8
|
+
table.column :id, :serial
|
9
|
+
table.column :person_id, :integer
|
10
|
+
table.column :password, :string
|
11
|
+
table.column :created_at, :date
|
12
|
+
table.column :disabled, :boolean, :default => true
|
13
|
+
end
|
14
|
+
##
|
15
|
+
# people
|
16
|
+
#
|
17
|
+
ActiveRecord::Base.connection.create_table :people, :force => true do |table|
|
18
|
+
table.column :id, :serial
|
19
|
+
table.column :first, :string, :null => false
|
20
|
+
table.column :last, :string, :null => false
|
21
|
+
table.column :email, :string, :null => false
|
22
|
+
end
|
23
|
+
##
|
24
|
+
# user_groups, join table
|
25
|
+
#
|
26
|
+
ActiveRecord::Base.connection.create_table :user_groups, :force => true do |table|
|
27
|
+
table.column :user_id, :integer
|
28
|
+
table.column :group_id, :integer
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# groups
|
33
|
+
#
|
34
|
+
ActiveRecord::Base.connection.create_table :groups, :force => true do |table|
|
35
|
+
table.column :id, :serial
|
36
|
+
table.column :title, :string
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# locations
|
41
|
+
#
|
42
|
+
ActiveRecord::Base.connection.create_table :locations, :force => true do |table|
|
43
|
+
table.column :id, :serial
|
44
|
+
table.column :name, :string
|
45
|
+
table.column :street, :string
|
46
|
+
table.column :type, :string
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# addresses
|
51
|
+
#
|
52
|
+
ActiveRecord::Base.connection.create_table :addresses, :force => true do |table|
|
53
|
+
table.column :id, :serial
|
54
|
+
table.column :addressable_type, :string
|
55
|
+
table.column :addressable_id, :integer
|
56
|
+
table.column :street, :string
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Mock a Model for testing data-types
|
61
|
+
#
|
62
|
+
ActiveRecord::Base.connection.create_table :data_types, :force => true do |table|
|
63
|
+
table.column :id, :serial
|
64
|
+
table.column :string_column, :string
|
65
|
+
table.column :decimal_column, :decimal
|
66
|
+
table.column :float_column, :float
|
67
|
+
table.column :date_column, :date
|
68
|
+
table.column :datetime_column, :datetime
|
69
|
+
table.column :time_column, :time
|
70
|
+
table.column :email, :string
|
71
|
+
table.column :integer_column, :integer
|
72
|
+
table.column :notnull_column, :string, :null => false
|
73
|
+
table.column :default_column, :boolean, :default => true
|
74
|
+
table.column :boolean_column, :boolean
|
75
|
+
end
|