lore 0.4.8 → 0.9.2
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/Manifest.txt +16 -7
- data/README.rdoc +91 -0
- data/benchmark/benchmark.sql +11 -0
- data/benchmark/results.txt +28 -0
- data/benchmark/select.rb +352 -0
- data/lib/lore.rb +22 -8
- data/lib/lore/adapters/context.rb +64 -0
- data/lib/lore/adapters/postgres-pr.rb +6 -0
- data/lib/lore/adapters/postgres-pr/connection.rb +93 -0
- data/lib/lore/adapters/postgres-pr/result.rb +63 -0
- data/lib/lore/{types.rb → adapters/postgres-pr/types.rb} +36 -0
- data/lib/lore/adapters/postgres.rb +24 -0
- data/lib/lore/adapters/postgres/connection.rb +81 -0
- data/lib/lore/adapters/postgres/result.rb +82 -0
- data/lib/lore/adapters/postgres/types.rb +91 -0
- data/lib/lore/bits.rb +18 -0
- data/lib/lore/cache/abstract_entity_cache.rb +2 -1
- data/lib/lore/cache/cacheable.rb +12 -177
- data/lib/lore/cache/memcache_entity_cache.rb +89 -0
- data/lib/lore/cache/memory_entity_cache.rb +77 -0
- data/lib/lore/cache/mmap_entity_cache.rb +2 -2
- data/lib/lore/cache/mmap_entity_cache_bork.rb +86 -0
- data/lib/lore/clause.rb +107 -35
- data/lib/lore/{exception → exceptions}/ambiguous_attribute.rb +2 -2
- data/lib/lore/{exception → exceptions}/cache_exception.rb +1 -1
- data/lib/lore/exceptions/database_exception.rb +16 -0
- data/lib/lore/{exception/invalid_parameter.rb → exceptions/invalid_field.rb} +7 -4
- data/lib/lore/exceptions/unknown_type.rb +18 -0
- data/lib/lore/exceptions/validation_failure.rb +71 -0
- data/lib/lore/gui/form_generator.rb +109 -60
- data/lib/lore/gui/lore_model_select_field.rb +1 -0
- data/lib/lore/migration.rb +84 -25
- data/lib/lore/model.rb +3 -18
- data/lib/lore/{aspect.rb → model/aspect.rb} +0 -0
- data/lib/lore/model/associations.rb +225 -0
- data/lib/lore/model/attribute_settings.rb +233 -0
- data/lib/lore/model/filters.rb +34 -0
- data/lib/lore/model/mockable.rb +62 -0
- data/lib/lore/{model_factory.rb → model/model_factory.rb} +68 -39
- data/lib/lore/model/model_instance.rb +382 -0
- data/lib/lore/{model_shortcuts.rb → model/model_shortcuts.rb} +7 -0
- data/lib/lore/model/polymorphic.rb +53 -0
- data/lib/lore/model/prepare.rb +97 -0
- data/lib/lore/model/table_accessor.rb +1016 -0
- data/lib/lore/query.rb +71 -0
- data/lib/lore/query_shortcuts.rb +43 -11
- data/lib/lore/strategies/table_delete.rb +115 -0
- data/lib/lore/strategies/table_insert.rb +146 -0
- data/lib/lore/strategies/table_select.rb +299 -0
- data/lib/lore/strategies/table_update.rb +155 -0
- data/lib/lore/validation/parameter_validator.rb +85 -26
- data/lib/lore/validation/type_validator.rb +34 -78
- data/{custom_models.rb → lore-0.9.2.gem} +0 -0
- data/lore.gemspec +26 -17
- data/spec/clause.rb +37 -0
- data/spec/fixtures/blank_models.rb +37 -0
- data/{test/model.rb → spec/fixtures/models.rb} +64 -41
- data/spec/fixtures/polymorphic_models.rb +68 -0
- data/spec/model_associations.rb +86 -0
- data/spec/model_create.rb +47 -0
- data/spec/model_definition.rb +151 -0
- data/spec/model_delete.rb +31 -0
- data/spec/model_inheritance.rb +50 -0
- data/spec/model_polymorphic.rb +85 -0
- data/spec/model_select.rb +101 -0
- data/spec/model_select_eager.rb +42 -0
- data/spec/model_union_select.rb +33 -0
- data/spec/model_update.rb +45 -0
- data/spec/model_validation.rb +20 -0
- data/spec/spec_db.sql +808 -0
- data/spec/spec_env.rb +19 -0
- data/spec/spec_helpers.rb +77 -0
- metadata +93 -82
- data/lib/lore/README.txt +0 -84
- data/lib/lore/behaviours/lockable.rb +0 -55
- data/lib/lore/behaviours/movable.rb +0 -72
- data/lib/lore/behaviours/paginated.rb +0 -31
- data/lib/lore/behaviours/versioned.rb +0 -36
- data/lib/lore/connection.rb +0 -152
- data/lib/lore/exception/invalid_klass_parameters.rb +0 -63
- data/lib/lore/exception/unknown_typecode.rb +0 -19
- data/lib/lore/result.rb +0 -119
- data/lib/lore/symbol.rb +0 -58
- data/lib/lore/table_accessor.rb +0 -1790
- data/lib/lore/table_deleter.rb +0 -116
- data/lib/lore/table_inserter.rb +0 -170
- data/lib/lore/table_instance.rb +0 -389
- data/lib/lore/table_selector.rb +0 -285
- data/lib/lore/table_updater.rb +0 -157
- data/lib/lore/validation.rb +0 -65
- data/lib/lore/validation/message.rb +0 -60
- data/lib/lore/validation/reason.rb +0 -52
- data/lore_test.log +0 -2366
- data/test/README +0 -31
- data/test/custom_models.rb +0 -18
- data/test/env.rb +0 -5
- data/test/prepare.rb +0 -37
- data/test/tc_aspect.rb +0 -58
- data/test/tc_cache.rb +0 -83
- data/test/tc_clause.rb +0 -104
- data/test/tc_deep_inheritance.rb +0 -49
- data/test/tc_factory.rb +0 -57
- data/test/tc_filter.rb +0 -37
- data/test/tc_form.rb +0 -32
- data/test/tc_model.rb +0 -140
- data/test/tc_prepare.rb +0 -44
- data/test/tc_refined_query.rb +0 -88
- data/test/tc_table_accessor.rb +0 -267
- data/test/tc_thread.rb +0 -100
- data/test/test_db.sql +0 -400
- data/test/test_lore.rb +0 -50
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
module Lore
|
|
3
|
-
module
|
|
3
|
+
module Exceptions
|
|
4
4
|
|
|
5
5
|
class Ambiguous_Attribute < ::Exception
|
|
6
6
|
|
|
7
7
|
def initialize(table_a, table_b, attribute)
|
|
8
|
-
@message =
|
|
8
|
+
@message = "Ambiguous attribute: #{attribute.inspect} exists in #{table_a} and #{table_b}. "
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
end # class
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
module Lore
|
|
3
|
-
module
|
|
3
|
+
module Exceptions
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class Invalid_Field < ::Exception
|
|
6
6
|
|
|
7
7
|
attr_reader :invalid_params, :reason
|
|
8
8
|
|
|
@@ -19,17 +19,20 @@ module Exception
|
|
|
19
19
|
}
|
|
20
20
|
result
|
|
21
21
|
end
|
|
22
|
+
def inspect
|
|
23
|
+
serialize.inspect
|
|
24
|
+
end
|
|
22
25
|
|
|
23
26
|
end
|
|
24
27
|
|
|
25
|
-
class Invalid_Types <
|
|
28
|
+
class Invalid_Types < Invalid_Field
|
|
26
29
|
def initialize(invalid_params)
|
|
27
30
|
super(invalid_params)
|
|
28
31
|
@reason = :type
|
|
29
32
|
end
|
|
30
33
|
end
|
|
31
34
|
|
|
32
|
-
class Unmet_Constraints <
|
|
35
|
+
class Unmet_Constraints < Invalid_Field
|
|
33
36
|
def initialize(invalid_params)
|
|
34
37
|
super(invalid_params)
|
|
35
38
|
@reason = :constraint
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
module Lore
|
|
3
|
+
module Exceptions
|
|
4
|
+
|
|
5
|
+
class Unknown_Type < ::Exception
|
|
6
|
+
|
|
7
|
+
attr_reader :code, :value
|
|
8
|
+
|
|
9
|
+
def initialize(type_code, value)
|
|
10
|
+
@code = type_code
|
|
11
|
+
@value = value
|
|
12
|
+
@message = "Unknown database type: #{type_code.to_s} for value #{value.inspect}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end # module
|
|
18
|
+
end # module
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
|
|
2
|
+
require('lore/exceptions/invalid_field')
|
|
3
|
+
|
|
4
|
+
module Lore
|
|
5
|
+
module Exceptions
|
|
6
|
+
|
|
7
|
+
# A validation failure consists of one or more Invalid_Field
|
|
8
|
+
# instances for every model field for which invalid values have
|
|
9
|
+
# been passed, e.g. on Model.create or Model.update.
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
#
|
|
13
|
+
# raise Validation_Failure.new(The_Model, {
|
|
14
|
+
# # Generic error. Example: :user_id => Lore.integer
|
|
15
|
+
# :table_foo => Invalid_Field.new( :the_attribute => :error_type )
|
|
16
|
+
# # Constraint error. Example: :email => :format
|
|
17
|
+
# :table bar => Unmet_Constraints.new( :the_attribute => :error_type )
|
|
18
|
+
# # Type error. Example: :user_id => Lore.integer or :user_id => :missing
|
|
19
|
+
# :table_batz => Invalid_Types.new( :the_attribute => :error_type )
|
|
20
|
+
# })
|
|
21
|
+
#
|
|
22
|
+
class Validation_Failure < ::Exception
|
|
23
|
+
|
|
24
|
+
# Instances of Exception::Invalid_Field
|
|
25
|
+
attr_reader :invalid_fields
|
|
26
|
+
# Model klass that failed validation
|
|
27
|
+
attr_reader :invalid_klass
|
|
28
|
+
|
|
29
|
+
def initialize(klass, invalid_params_hash)
|
|
30
|
+
# Instances of Exception::Invalid_Field
|
|
31
|
+
@invalid_fields = invalid_params_hash
|
|
32
|
+
@invalid_klass = klass
|
|
33
|
+
@message = "#{self.class.to_s}: #{@invalid_fields.inspect}"
|
|
34
|
+
log()
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def log()
|
|
38
|
+
# {{{
|
|
39
|
+
Lore.logger.error { "====== VALIDATION FAILURE ===========" }
|
|
40
|
+
Lore.logger.error { "Invalid field values for klass #{@invalid_klass}: " }
|
|
41
|
+
Lore.logger.error { 'Invalid field values are: ' }
|
|
42
|
+
@invalid_fields.each_pair { |table, ip|
|
|
43
|
+
Lore.logger.error { " |- Table: #{table}: #{ip.inspect}" }
|
|
44
|
+
}
|
|
45
|
+
Lore.logger.error { 'Required attributes are: ' }
|
|
46
|
+
@invalid_klass.__attributes__.required.each_pair { |table, ip|
|
|
47
|
+
Lore.logger.error { " |- Table: #{table}: #{ip.inspect}" }
|
|
48
|
+
}
|
|
49
|
+
end # }}}
|
|
50
|
+
|
|
51
|
+
def serialize()
|
|
52
|
+
# {{{
|
|
53
|
+
serials = {}
|
|
54
|
+
@invalid_fields.each_pair { |table, invalid_param|
|
|
55
|
+
serials[table] = invalid_param.serialize
|
|
56
|
+
}
|
|
57
|
+
return serials
|
|
58
|
+
end # def }}}
|
|
59
|
+
|
|
60
|
+
def inspect()
|
|
61
|
+
"Model(#{@invalid_klass}) => #{@invalid_fields.serialize} " <<
|
|
62
|
+
"Required: #{@invalid_klass.__attributes__.required.inspect}"
|
|
63
|
+
end
|
|
64
|
+
alias explain serialize
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
end # module
|
|
70
|
+
end # module
|
|
71
|
+
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
require('
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
require('rubygems')
|
|
3
|
+
require('aurita-gui')
|
|
4
|
+
require('lore')
|
|
5
|
+
require('lore/gui/lore_model_select_field')
|
|
5
6
|
|
|
6
7
|
module Lore
|
|
7
8
|
module GUI
|
|
@@ -17,9 +18,10 @@ module GUI
|
|
|
17
18
|
# puts generator.form
|
|
18
19
|
#
|
|
19
20
|
class Form_Generator
|
|
21
|
+
include Aurita::GUI
|
|
20
22
|
|
|
21
23
|
attr_reader :form, :klass
|
|
22
|
-
attr_accessor :custom_elements, :labels, :params
|
|
24
|
+
attr_accessor :custom_elements, :labels, :params, :form_class
|
|
23
25
|
|
|
24
26
|
def initialize(klass=nil)
|
|
25
27
|
@klass = klass
|
|
@@ -27,6 +29,7 @@ module GUI
|
|
|
27
29
|
@params = {}
|
|
28
30
|
@custom_elements = {}
|
|
29
31
|
@form = false
|
|
32
|
+
@form_class = Aurita::GUI::Form
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
def form
|
|
@@ -34,83 +37,129 @@ module GUI
|
|
|
34
37
|
@form
|
|
35
38
|
end
|
|
36
39
|
|
|
40
|
+
@@type_field_map = {
|
|
41
|
+
:default => Proc.new { |l,f| Input_Field.new(:label => l, :name => f) },
|
|
42
|
+
Lore::PG_BOOL => Proc.new { |l,f| Boolean_Field.new(:label => l, :name => f) },
|
|
43
|
+
Lore::PG_VARCHAR => Proc.new { |l,f| Input_Field.new(:label => l, :name => f) },
|
|
44
|
+
Lore::PG_SMALLINT => Proc.new { |l,f| Input_Field.new(:label => l, :name => f) },
|
|
45
|
+
Lore::PG_INT => Proc.new { |l,f| Input_Field.new(:label => l, :name => f) },
|
|
46
|
+
Lore::PG_TEXT => Proc.new { |l,f| Textarea_Field.new(:label => l, :name => f) },
|
|
47
|
+
|
|
48
|
+
Lore::PG_TIMESTAMP_TIMEZONE => Proc.new { |l,f| Datetime_Field.new(:label => l, :name => f,
|
|
49
|
+
:date_format => 'dmy',
|
|
50
|
+
:time_format => 'hms',
|
|
51
|
+
:year_range => (2009..2020)) },
|
|
52
|
+
|
|
53
|
+
Lore::PG_TIMESTAMP => Proc.new { |l,f| Datetime_Field.new(:label => l, :name => f,
|
|
54
|
+
:date_format => 'dmy',
|
|
55
|
+
:time_format => 'hms',
|
|
56
|
+
:year_range => (2009..2020)) },
|
|
57
|
+
|
|
58
|
+
Lore::PG_DATE => Proc.new { |l,f| Date_Field.new(:label => l, :name => f,
|
|
59
|
+
:date_format => 'dmy',
|
|
60
|
+
:year_range => (2009..2020)) },
|
|
61
|
+
|
|
62
|
+
Lore::PG_TIME => Proc.new { |l,f| Time_Field.new(:label => l, :name => f,
|
|
63
|
+
:time_format => 'hm') }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected
|
|
67
|
+
|
|
68
|
+
def field_for(type, params)
|
|
69
|
+
element = @@type_field_map[type]
|
|
70
|
+
element ||= @@type_field_map[:default]
|
|
71
|
+
return element.call(params[:label], params[:name])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
public
|
|
75
|
+
|
|
37
76
|
def generate
|
|
38
|
-
@form =
|
|
77
|
+
@form = @form_class.new(@params)
|
|
78
|
+
model_labels = @klass.attribute_labels if @klass.respond_to?(:attribute_labels)
|
|
79
|
+
model_labels ||= {}
|
|
80
|
+
|
|
81
|
+
@klass.get_fields.each_pair { |table, attributes|
|
|
39
82
|
|
|
40
|
-
@klass.get_attributes.each_pair { |table, attributes|
|
|
41
83
|
attributes.each { |attribute|
|
|
42
|
-
label_tag = table.gsub('.','--')
|
|
84
|
+
label_tag = "#{table.gsub('.','--')}--#{attribute}"
|
|
43
85
|
label = @labels[label_tag]
|
|
44
|
-
label
|
|
45
|
-
|
|
46
|
-
|
|
86
|
+
label = attribute.to_s.capitalize if label.to_s == ''
|
|
87
|
+
|
|
88
|
+
full_attrib = "#{table}.#{attribute}"
|
|
89
|
+
field_name = full_attrib
|
|
47
90
|
form_element = false
|
|
91
|
+
|
|
92
|
+
attributes = @klass.__attributes__
|
|
93
|
+
associations = @klass.__associations__
|
|
94
|
+
|
|
95
|
+
constraints = attributes.constraints
|
|
96
|
+
constraints = constraints[table] if constraints
|
|
97
|
+
constraints = constraints[attribute] if constraints
|
|
98
|
+
|
|
99
|
+
aggregate_klasses = associations.aggregate_klasses
|
|
100
|
+
has_a_klasses = associations.has_a
|
|
101
|
+
implicits = attributes.implicit
|
|
102
|
+
ecplicits = attributes.explicit
|
|
103
|
+
requireds = attributes.required
|
|
104
|
+
primary_keys = attributes.primary_keys
|
|
105
|
+
attribute_types = attributes.types
|
|
48
106
|
|
|
49
|
-
# @custom_elements is a hash mapping attribute
|
|
50
|
-
# Custom_Element instances.
|
|
107
|
+
# @custom_elements is a hash mapping attribute
|
|
108
|
+
# names to Custom_Element instances.
|
|
51
109
|
if ((@custom_elements[table]) and
|
|
52
110
|
(@custom_elements[table][attribute])) then
|
|
53
111
|
|
|
54
|
-
form_element = @custom_elements[table][attribute].new(
|
|
112
|
+
form_element = @custom_elements[table][attribute].new(:label => label,
|
|
113
|
+
:id => full_attrib,
|
|
114
|
+
:name => field_name)
|
|
55
115
|
|
|
56
|
-
elsif (
|
|
57
|
-
|
|
58
|
-
(
|
|
59
|
-
|
|
60
|
-
(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
116
|
+
elsif (primary_keys[table].nil? or # Ignore primary key attributes
|
|
117
|
+
!primary_keys[table].include? attribute) and
|
|
118
|
+
(implicits[table].nil? or # Ignore implicit attributes
|
|
119
|
+
!implicits[table].include? attribute) and
|
|
120
|
+
(has_a_klasses.nil? or # Ignore attributes aggregated via has_a associations (added later)
|
|
121
|
+
has_a_klasses[full_attrib].nil?)
|
|
122
|
+
# and (hidden_attributes[table].nil? or # Ignore otherwise hidden attributes
|
|
123
|
+
# !hidden_attributes[table].include? attribute)
|
|
64
124
|
then
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
form_element = Radio_Field.new(:label => label,
|
|
69
|
-
:name => field_name,
|
|
70
|
-
:options => { 't' => 'yes', 'f' => 'no' } )
|
|
71
|
-
|
|
72
|
-
when Lore::PG_SMALLINT || Lore::PG_INT
|
|
73
|
-
form_element = Input_Field.new(:label => label, :name => field_name)
|
|
74
|
-
when Lore::PG_VARCHAR
|
|
75
|
-
form_element = Input_Field.new(:label => label, :name => field_name)
|
|
76
|
-
when Lore::PG_TEXT
|
|
77
|
-
form_element = Textarea_Field.new(:label => label, :name => field_name)
|
|
78
|
-
when Lore::PG_TIMESTAMP_TIMEZONE
|
|
79
|
-
form_element = Datetime_Field.new(:label => label, :name => field_name, :date_format => 'dmy', :time_format => 'hms', :year_range => (2009..2020))
|
|
80
|
-
when Lore::PG_DATE
|
|
81
|
-
form_element = Date_Field.new(:label => label, :name => field_name, :date_format => 'dmy', :year_range => (2009..2020))
|
|
82
|
-
else
|
|
83
|
-
form_element = Input_Field.new(:label => label, :name => field_name)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
elsif (!@klass.get_has_a_klasses.nil? and
|
|
87
|
-
!@klass.get_has_a_klasses[full_attrib].nil?)
|
|
125
|
+
form_element = field_for(attribute_types[table][attribute], :name => field_name, :label => label)
|
|
126
|
+
elsif (!has_a_klasses.nil? and
|
|
127
|
+
!has_a_klasses[full_attrib].nil?)
|
|
88
128
|
then
|
|
89
|
-
foreign_klass =
|
|
90
|
-
form_element =
|
|
129
|
+
foreign_klass = has_a_klasses[full_attrib]
|
|
130
|
+
form_element = Aurita::GUI::Lore_Model_Select_Field.new(foreign_klass, :label => label, :name => field_name)
|
|
91
131
|
|
|
92
|
-
elsif (
|
|
93
|
-
|
|
132
|
+
elsif (!aggregate_klasses.nil? and
|
|
133
|
+
!aggregate_klasses[full_attrib].nil?)
|
|
94
134
|
then
|
|
95
|
-
foreign_klass =
|
|
96
|
-
form_element =
|
|
135
|
+
foreign_klass = aggregate_klasses[full_attrib]
|
|
136
|
+
form_element = Aurita::GUI::Lore_Model_Select_Field.new(foreign_klass, :label => label, :name => field_name)
|
|
97
137
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
elsif (!@klass.get_explicit_attributes[table].nil? and
|
|
101
|
-
@klass.get_explicit_attributes[table].include? attribute)
|
|
102
|
-
then
|
|
103
|
-
form_element = Hidden_Field.new(:name => field_name)
|
|
104
|
-
|
|
105
|
-
elsif (!@klass.get_implicit_attributes[table].nil? and
|
|
106
|
-
@klass.get_implicit_attributes[table].include? attribute)
|
|
138
|
+
elsif (!implicits[table].nil? and
|
|
139
|
+
implicits[table].include? attribute)
|
|
107
140
|
then
|
|
108
141
|
# Implicit field, ignored
|
|
109
142
|
end
|
|
110
143
|
|
|
111
|
-
|
|
144
|
+
if form_element then
|
|
145
|
+
form_element.data_type = attribute_types[table][attribute]
|
|
146
|
+
if(!requireds[table].nil? and
|
|
147
|
+
requireds[table].include? attribute) then
|
|
148
|
+
form_element.required!
|
|
149
|
+
end
|
|
150
|
+
if constraints then
|
|
151
|
+
if constraints[:minlength] then
|
|
152
|
+
end
|
|
153
|
+
if constraints[:maxlength] then
|
|
154
|
+
end
|
|
155
|
+
if constraints[:format] then
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
@form.add(form_element)
|
|
159
|
+
end
|
|
112
160
|
}
|
|
113
161
|
}
|
|
162
|
+
return @form
|
|
114
163
|
end
|
|
115
164
|
|
|
116
165
|
end # class
|
data/lib/lore/migration.rb
CHANGED
|
@@ -1,45 +1,104 @@
|
|
|
1
1
|
|
|
2
|
+
require('lore/types')
|
|
3
|
+
require('lore/model/model_factory')
|
|
4
|
+
|
|
2
5
|
module Lore
|
|
3
6
|
|
|
4
7
|
|
|
5
8
|
# Usage:
|
|
6
9
|
#
|
|
7
|
-
#
|
|
10
|
+
# class User_Profile_Migration < Lore::Migration
|
|
8
11
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
12
|
+
# def up
|
|
13
|
+
# create_table(:user_profile) {
|
|
14
|
+
# schema :public
|
|
15
|
+
# primary_key :user_profile_id, :user_profile_id_seq
|
|
16
|
+
# index :user_name
|
|
17
|
+
#
|
|
18
|
+
# user_name Lore::Type.varchar(50), :null => false, :unique => true
|
|
19
|
+
# is_admin Lore::Type.boolean, :null => false, :default => false
|
|
20
|
+
# registered Lore::Type.timestamp, :null => false, :default => 'now()'
|
|
21
|
+
# }
|
|
22
|
+
# end
|
|
15
23
|
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
24
|
+
# def down
|
|
25
|
+
# drop_table(:user_profile)
|
|
26
|
+
# drop_sequence(:user_profile_id_seq)
|
|
27
|
+
# end
|
|
20
28
|
#
|
|
21
|
-
#
|
|
22
|
-
# bootstrap()
|
|
23
|
-
# My_Model.create(:foo => 23, :bar => 123)
|
|
24
|
-
# end
|
|
29
|
+
# end
|
|
25
30
|
#
|
|
26
|
-
# end
|
|
27
31
|
#
|
|
28
|
-
|
|
32
|
+
class Migration
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
attr_reader :primary_keys, :schema, :table, :fields, :field_params, :indices, :drop_tables
|
|
35
|
+
|
|
36
|
+
def initialize()
|
|
37
|
+
@primary_keys = []
|
|
38
|
+
@sequences = {}
|
|
39
|
+
@fields = []
|
|
40
|
+
@field_params = {}
|
|
41
|
+
@indices = []
|
|
42
|
+
@drop_tables = []
|
|
43
|
+
@drop_sequences = []
|
|
44
|
+
@constraints = []
|
|
32
45
|
end
|
|
33
46
|
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
@
|
|
37
|
-
|
|
47
|
+
def create_table(table_name, schema=:public, &block)
|
|
48
|
+
instance_eval(&block)
|
|
49
|
+
@table = table_name
|
|
50
|
+
factory = Model_Factory.new(table_name)
|
|
51
|
+
@primary_keys.each { |p|
|
|
52
|
+
factory.add_attribute(p, :null => false, :type => Lore::Type.integer)
|
|
53
|
+
factory.add_primary_key(:attribute => p,
|
|
54
|
+
:key_name => "#{table_name}_pkey",
|
|
55
|
+
:sequence => @sequences[p] )
|
|
56
|
+
}
|
|
57
|
+
@fields.each { |f|
|
|
58
|
+
factory.add_attribute(f, @field_params[f])
|
|
38
59
|
}
|
|
60
|
+
factory.build_table
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def drop_table(table_name)
|
|
64
|
+
@drop_tables << table_name
|
|
65
|
+
end
|
|
66
|
+
def drop_sequence(sequence_name)
|
|
67
|
+
@drop_sequences << sequence_name
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def up()
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def down()
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def primary_key(key_name, sequence_name=nil)
|
|
77
|
+
key_name = key_name.to_sym
|
|
78
|
+
@primary_keys << key_name
|
|
79
|
+
@sequences[key_name] = sequence_name.to_sym if sequence_name
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def schema(schema_name)
|
|
83
|
+
@schema = schema_name
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def add_field(field_name, type, params={})
|
|
87
|
+
@fields << field_name
|
|
88
|
+
@field_params[field_name] = params
|
|
89
|
+
@field_params[field_name][:type] = type
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def add_constraint(constraint)
|
|
93
|
+
@constraints << constraint
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def index(field_name)
|
|
97
|
+
@indices << field_name
|
|
39
98
|
end
|
|
40
99
|
|
|
41
|
-
def
|
|
42
|
-
|
|
100
|
+
def method_missing(field_name, type, params={})
|
|
101
|
+
add_field(field_name, type, params)
|
|
43
102
|
end
|
|
44
103
|
|
|
45
104
|
end
|