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
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
require 'spec_env'
|
|
3
|
+
include Lore::Spec_Fixtures::Models
|
|
4
|
+
|
|
5
|
+
describe(Lore::Table_Accessor) do
|
|
6
|
+
before do
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "does not create records for aggregated models on create procedures" do
|
|
10
|
+
motor = Motor.create(:motor_name => 'Gaso-Suck 3000', :kw => 200)
|
|
11
|
+
|
|
12
|
+
vehicle = Motorized_Vehicle.create(:name => 'vehicle_name',
|
|
13
|
+
:num_doors => 3,
|
|
14
|
+
:num_seats => 5,
|
|
15
|
+
:owner_id => 0,
|
|
16
|
+
:maxspeed => 170,
|
|
17
|
+
:motor_id => motor.pkey)
|
|
18
|
+
|
|
19
|
+
vehicle.name.should == 'vehicle_name'
|
|
20
|
+
vehicle.motor_name.should == 'Gaso-Suck 3000'
|
|
21
|
+
vehicle.kw.should == 200
|
|
22
|
+
vehicle.maxspeed.should == "170km/h"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "automatically distributes attribute values on base tables on create procedures" do
|
|
26
|
+
|
|
27
|
+
motor = Motor.create(:motor_name => 'Lawn Mower Ultra', :kw => 20)
|
|
28
|
+
|
|
29
|
+
car = Car.create(:name => 'vehicle_name',
|
|
30
|
+
:num_doors => 5,
|
|
31
|
+
:num_seats => 4,
|
|
32
|
+
:owner_id => 0,
|
|
33
|
+
:motor_id => motor.pkey,
|
|
34
|
+
:car_type_id => Car_Type.create(:type_name => 'Roadkill X1000').car_type_id,
|
|
35
|
+
:maxspeed => 180)
|
|
36
|
+
car.num_doors.should == 5
|
|
37
|
+
car.name.should == 'vehicle_name'
|
|
38
|
+
car.maxspeed.should == '180km/h'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "provides a before_create hook" do
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "provides an after_create hook" do
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
|
|
2
|
+
require 'spec_env'
|
|
3
|
+
include Lore::Spec_Fixtures::Blank_Models
|
|
4
|
+
|
|
5
|
+
describe(Lore::Table_Accessor) do
|
|
6
|
+
before do
|
|
7
|
+
# Lore::Spec_Fixtures::Models::Vehicle.delete_all
|
|
8
|
+
# Lore::Spec_Fixtures::Models::Car.delete_all
|
|
9
|
+
# Lore::Spec_Fixtures::Models::Motorbike.delete_all
|
|
10
|
+
# Lore::Spec_Fixtures::Models::Owner.delete_all
|
|
11
|
+
# Lore::Spec_Fixtures::Models::Vehicle_Owner.delete_all
|
|
12
|
+
# Lore::Spec_Fixtures::Models::Car_Type.delete_all
|
|
13
|
+
# Lore::Spec_Fixtures::Models::Garage.delete_all
|
|
14
|
+
# Lore::Spec_Fixtures::Models::Motor.delete_all
|
|
15
|
+
# Lore::Spec_Fixtures::Models::Motorized_Vehicle.delete_all
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "is assigned to a base table" do
|
|
19
|
+
Vehicle.table :vehicle, :public
|
|
20
|
+
Car.table :car, :public
|
|
21
|
+
Motorbike.table :motorbike, :public
|
|
22
|
+
Owner.table :owner, :public
|
|
23
|
+
Vehicle_Owner.table :vehicle_owner, :public
|
|
24
|
+
Car_Type.table :car_type, :public
|
|
25
|
+
Garage.table :garage, :public
|
|
26
|
+
Motor.table :motor, :public
|
|
27
|
+
Motorized_Vehicle.table :motorized, :public
|
|
28
|
+
|
|
29
|
+
Car.table_name.should == 'public.car'
|
|
30
|
+
Vehicle.table_name.should == 'public.vehicle'
|
|
31
|
+
Motorbike.table_name.should == 'public.motorbike'
|
|
32
|
+
Owner.table_name.should == 'public.owner'
|
|
33
|
+
Vehicle_Owner.table_name.should == 'public.vehicle_owner'
|
|
34
|
+
Car_Type.table_name.should == 'public.car_type'
|
|
35
|
+
Garage.table_name.should == 'public.garage'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "loads attribute fields automatically as array of symbols" do
|
|
39
|
+
Vehicle.get_fields.should == { 'public.vehicle' => [ :id, :manuf_id, :num_seats, :maxspeed, :name, :owner_id ] }
|
|
40
|
+
Vehicle.get_fields_flat.should == [ :id, :manuf_id, :num_seats, :maxspeed, :name, :owner_id ]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "has one or more primary key attributes" do
|
|
44
|
+
Vehicle.primary_key :id, :vehicle_id_seq
|
|
45
|
+
Car.primary_key :id, :car_id_seq
|
|
46
|
+
Motorbike.primary_key :motorbike_id, :motorbike_id_seq
|
|
47
|
+
Owner.primary_key :owner_id, :owner_id_seq
|
|
48
|
+
Car_Type.primary_key :car_type_id, :car_type_id_seq
|
|
49
|
+
Garage.primary_key :garage_id, :garage_id_seq
|
|
50
|
+
Motor.primary_key :id, :motor_id_seq
|
|
51
|
+
Motorized_Vehicle.primary_key :id, :motorized_id_seq
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "may have required attributes" do
|
|
55
|
+
Car.expects :num_seats
|
|
56
|
+
# does the same
|
|
57
|
+
Car.validates :num_doors, :mandatory => true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "allows adding other models as aggregates" do
|
|
61
|
+
Car.aggregates Car_Type, :car_type_id
|
|
62
|
+
Motorized_Vehicle.is_a Vehicle, :vehicle_id
|
|
63
|
+
Motorized_Vehicle.aggregates Motor, :motor_id
|
|
64
|
+
Motorized_Vehicle.__associations__.base_klasses.values.should == [ [ Vehicle, [ :vehicle_id ] ] ]
|
|
65
|
+
Motorized_Vehicle.__associations__.aggregate_klasses.values.should == [ [ Motor , [ :motor_id ] ] ]
|
|
66
|
+
Motorized_Vehicle.__associations__.joined_models.values.should == [ [ Vehicle, [ :vehicle_id ] ] , [ Motor, [ :motor_id ] ] ]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "can be derived from one base model or more" do
|
|
70
|
+
Car.is_a Motorized_Vehicle, :motorized_id
|
|
71
|
+
Motorbike.is_a Vehicle, :vehicle_id
|
|
72
|
+
|
|
73
|
+
Car.is_a?(Motorized_Vehicle).should == true
|
|
74
|
+
Car.is_a?(Vehicle).should == true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "inherits attribute fields from joined base models" do
|
|
78
|
+
expected_fields = {
|
|
79
|
+
'public.vehicle' => [ :id, :manuf_id, :num_seats, :maxspeed, :name, :owner_id ],
|
|
80
|
+
'public.car_type' => [ :car_type_id, :type_name ],
|
|
81
|
+
'public.car' => [ :id, :motorized_id, :car_type_id, :num_doors ],
|
|
82
|
+
'public.motorized' => [ :vehicle_id, :motor_id, :id ],
|
|
83
|
+
'public.motor' => [ :id, :motor_name, :kw ]
|
|
84
|
+
}
|
|
85
|
+
Car.get_fields.should_be expected_fields
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "may have composed primary keys" do
|
|
89
|
+
Vehicle_Owner.primary_key :vehicle_id
|
|
90
|
+
Vehicle_Owner.primary_key :owner_id
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "may have non-sequential primary keys" do
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "allows arbitrary naming of keys" do
|
|
97
|
+
Vehicle.has_a Owner, :owner
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "provides input and output filters for attribute values" do
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "defines attributes that cannot be set manually as explicit" do
|
|
104
|
+
expected = {
|
|
105
|
+
# has_a foreign keys :manuf_id and owner are explicit:
|
|
106
|
+
'public.vehicle' => [ :manuf_id, :num_seats, :maxspeed, :name, :owner_id ],
|
|
107
|
+
# Aggregate foreign key :motor_id is explicit:
|
|
108
|
+
'public.motorized' => [ :motor_id ],
|
|
109
|
+
# Aggregate foreign key :car_type_id is explicit:
|
|
110
|
+
'public.car' => [ :car_type_id, :num_doors ]
|
|
111
|
+
|
|
112
|
+
# Aggregated models do not extend implicit or explicit fields!
|
|
113
|
+
# 'public.motor' => [ :motor_name ],
|
|
114
|
+
# 'public.car_type' => [ :type_name ],
|
|
115
|
+
}
|
|
116
|
+
Car.__attributes__.explicit.should_be expected
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "defines all attributes that are not explicit as implicit" do
|
|
120
|
+
expected = {
|
|
121
|
+
'public.vehicle' => [ :id ],
|
|
122
|
+
'public.motorized' => [ :id, :vehicle_id ],
|
|
123
|
+
'public.car' => [ :id, :motorized_id ]
|
|
124
|
+
|
|
125
|
+
# Aggregated models do not extend implicit or explicit fields!
|
|
126
|
+
# 'public.motor' => [ :id ],
|
|
127
|
+
# 'public.car_type' => [ :car_type_id ],
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
Car.__attributes__.implicit.should_be expected
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it "provides a before_select hook" do
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "provides validating presence of attribute values" do
|
|
137
|
+
Vehicle.validates :name, :mandatory => true
|
|
138
|
+
# .expects does the same
|
|
139
|
+
Car.expects :num_doors
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "provides validating attribute values by length" do
|
|
143
|
+
Vehicle.validates :name, :maxlength => 20
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it "provides validating attribute values by format" do
|
|
147
|
+
Vehicle.validates :name, :format => NAME_FORMAT
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
require 'spec_env'
|
|
3
|
+
include Lore::Spec_Fixtures::Models
|
|
4
|
+
|
|
5
|
+
include Spec_Model_Select_Helpers
|
|
6
|
+
|
|
7
|
+
describe(Lore::Table_Accessor) do
|
|
8
|
+
|
|
9
|
+
it "does not delete records for aggregated models on delete procedures" do
|
|
10
|
+
manuf = Manufacturer.create(:name => 'Major Motors')
|
|
11
|
+
vehicle = Car.create(car_create_values(:name => 'wombat', :manuf_id => manuf.pkey))
|
|
12
|
+
manuf_id = vehicle.manufacturer.manuf_id
|
|
13
|
+
motor_id = vehicle.motor_id
|
|
14
|
+
manuf = Manufacturer.get(manuf_id)
|
|
15
|
+
vehicle.motor_name.should == 'Mock Motor'
|
|
16
|
+
vehicle.delete!
|
|
17
|
+
manuf = Manufacturer.get(manuf_id) # Re-Select
|
|
18
|
+
motor = Motor.get(motor_id) # Re-Select
|
|
19
|
+
manuf.should_not == false
|
|
20
|
+
motor.should_not == false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "deletes single Model instances on Model#delete" do
|
|
24
|
+
car = Car.create(car_create_values(:name => 'delete_me!'))
|
|
25
|
+
car_id = car.pkey
|
|
26
|
+
car.delete
|
|
27
|
+
Car.get(car_id).should == false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
require 'spec_env'
|
|
3
|
+
include Lore::Spec_Fixtures::Models
|
|
4
|
+
|
|
5
|
+
describe(Lore::Table_Accessor) do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
flush_test_data()
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "provides single inheritance" do
|
|
12
|
+
Motorized_Vehicle.is_a?(Vehicle).should == true
|
|
13
|
+
Car.is_a?(Vehicle).should == true
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "provides multiple inheritance" do
|
|
18
|
+
Autobot.is_a?(Car).should == true
|
|
19
|
+
Autobot.is_a?(Robot).should == true
|
|
20
|
+
|
|
21
|
+
motor = Motor.create(:motor_name => 'Autobot Car Motor',
|
|
22
|
+
:kw => 239)
|
|
23
|
+
car_type = Car_Type.create(:type_name => 'Autobot Car')
|
|
24
|
+
|
|
25
|
+
t = Autobot.create(# Attributes for Vehicle
|
|
26
|
+
:name => 'Autobot',
|
|
27
|
+
:num_seats => 4,
|
|
28
|
+
:maxspeed => 190,
|
|
29
|
+
:owner_id => 23,
|
|
30
|
+
:manuf_id => 42,
|
|
31
|
+
# Attributes for Motorized
|
|
32
|
+
:motor_type => 'brushless',
|
|
33
|
+
:motor_id => motor.pkey,
|
|
34
|
+
# Attributes for Car
|
|
35
|
+
:car_type_id => car_type.pkey,
|
|
36
|
+
:num_doors => 5,
|
|
37
|
+
# Attributes for Robot
|
|
38
|
+
:robot_class => 'Exoskel X3000',
|
|
39
|
+
:locomotion_type => 'bipedal')
|
|
40
|
+
|
|
41
|
+
t.name.should == 'autobot'
|
|
42
|
+
t.num_seats.should == 4
|
|
43
|
+
t.manuf_id.should == 42
|
|
44
|
+
t.motor_type.should == 'brushless'
|
|
45
|
+
t.locomotion_type.should == 'bipedal'
|
|
46
|
+
|
|
47
|
+
t.transform.should == 'Autobot transformed!'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
|
|
2
|
+
require 'spec_env'
|
|
3
|
+
include Lore::Spec_Fixtures::Polymorphic_Models
|
|
4
|
+
|
|
5
|
+
describe(Lore::Table_Accessor) do
|
|
6
|
+
before do
|
|
7
|
+
flush_test_data()
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "implements the Liskov substitution principle" do
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "implements inverse polymorphism" do
|
|
14
|
+
|
|
15
|
+
Asset.is_polymorphic?.should == true
|
|
16
|
+
Media_Asset.is_polymorphic?.should == false
|
|
17
|
+
Document_Asset.is_polymorphic?.should == false
|
|
18
|
+
|
|
19
|
+
expected = { 'public.asset' => :model }
|
|
20
|
+
Media_Asset.__associations__.polymorphics.should_be expected
|
|
21
|
+
|
|
22
|
+
Asset.__associations__.concrete_models.length.should == 2
|
|
23
|
+
|
|
24
|
+
5.times {
|
|
25
|
+
info = Media_Asset_Info.create(:description => 'a media file')
|
|
26
|
+
media = Media_Asset.create(:folder => '/tmp/spec/media/',
|
|
27
|
+
:filename => 'music.ogg',
|
|
28
|
+
:hits => 123,
|
|
29
|
+
:info_id => info.pkey,
|
|
30
|
+
:media_type => 'sound')
|
|
31
|
+
info = Document_Asset_Info.create(:relevance => 5)
|
|
32
|
+
docum = Document_Asset.create(:folder => '/tmp/spec/docs/',
|
|
33
|
+
:filename => 'sample.txt',
|
|
34
|
+
:info_id => info.pkey,
|
|
35
|
+
:doctype => 'plaintext')
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
polymorphics = Asset.find(10).polymorphic.sort_by(Asset.asset_id, :desc).entities
|
|
39
|
+
polymorphics.length.should == 10
|
|
40
|
+
polymorphics.each_with_index { |a,idx|
|
|
41
|
+
expected = (idx % 2 == 1)? true : false
|
|
42
|
+
a.is_a?(Media_Asset).should == expected
|
|
43
|
+
a.is_a?(Document_Asset).should == !expected
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "Handles inherited fields like in regular selects" do
|
|
48
|
+
|
|
49
|
+
info = Media_Asset_Info.create(:description => 'a media file')
|
|
50
|
+
media = Media_Asset.create(:folder => '/tmp/spec/media/',
|
|
51
|
+
:filename => 'music.ogg',
|
|
52
|
+
:hits => 123,
|
|
53
|
+
:info_id => info.pkey,
|
|
54
|
+
:media_type => 'sound')
|
|
55
|
+
info = Document_Asset_Info.create(:relevance => 5)
|
|
56
|
+
docum = Document_Asset.create(:folder => '/tmp/spec/docs/',
|
|
57
|
+
:filename => 'sample.txt',
|
|
58
|
+
:info_id => info.pkey,
|
|
59
|
+
:doctype => 'plaintext')
|
|
60
|
+
|
|
61
|
+
media_polymorphic_id = media.asset_id
|
|
62
|
+
docum_polymorphic_id = docum.asset_id
|
|
63
|
+
|
|
64
|
+
# Select an Asset which is known to be a concrete
|
|
65
|
+
# Media_Asset:
|
|
66
|
+
asset = Asset.polymorphic_select { |a|
|
|
67
|
+
a.where(Asset.asset_id.is media_polymorphic_id)
|
|
68
|
+
a.limit(1)
|
|
69
|
+
}.first
|
|
70
|
+
asset.is_a?(Media_Asset).should == true
|
|
71
|
+
asset.is_a?(Asset).should == true
|
|
72
|
+
asset.media_type.should == 'sound'
|
|
73
|
+
|
|
74
|
+
# Select an Asset which is known to be a concrete
|
|
75
|
+
# Document_Asset:
|
|
76
|
+
asset = Asset.polymorphic_select { |a|
|
|
77
|
+
a.where(Asset.asset_id.is docum_polymorphic_id)
|
|
78
|
+
a.limit(1)
|
|
79
|
+
}.first
|
|
80
|
+
asset.is_a?(Document_Asset).should == true
|
|
81
|
+
asset.is_a?(Asset).should == true
|
|
82
|
+
asset.doctype.should == 'plaintext'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
|
|
2
|
+
require 'spec_env'
|
|
3
|
+
include Lore::Spec_Fixtures::Models
|
|
4
|
+
|
|
5
|
+
include Spec_Model_Select_Helpers
|
|
6
|
+
|
|
7
|
+
describe(Lore::Table_Accessor) do
|
|
8
|
+
before do
|
|
9
|
+
flush_test_data()
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should provide a DSL for selects" do
|
|
13
|
+
|
|
14
|
+
for index in 0...3 do
|
|
15
|
+
Car.create(car_create_values(:name => "Car #{index}" ))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
expected = Car.select_value('count(*)') { |c| c.where(true) }
|
|
19
|
+
expected.to_i.should == 3
|
|
20
|
+
|
|
21
|
+
car = Car.select { |c|
|
|
22
|
+
c.where((c.name == "car1").or(c.name == "car2"))
|
|
23
|
+
c.limit(1)
|
|
24
|
+
}.first
|
|
25
|
+
car.name.should == "car1"
|
|
26
|
+
|
|
27
|
+
car = Car.select { |c|
|
|
28
|
+
c.where((c.name == "car1").or(c.name == "car2"))
|
|
29
|
+
c.limit(1, 1)
|
|
30
|
+
}.first
|
|
31
|
+
car.name.should == "car2"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "provides convenience methods for selects" do
|
|
35
|
+
car_org = Car.create(car_create_values(:name => "The Car" ))
|
|
36
|
+
car_sel = Car.find(1).with(Car.name == "thecar").entity
|
|
37
|
+
car_org.name.should == "thecar"
|
|
38
|
+
car_sel.name.should == "thecar"
|
|
39
|
+
car_org.should == car_sel
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "allows arbitrary joins with other models" do
|
|
43
|
+
|
|
44
|
+
cf = Car_Features.create(:car_id => Car.create(car_create_values(:name => 'fordmondeo')).pkey,
|
|
45
|
+
:color => 'red')
|
|
46
|
+
|
|
47
|
+
res = Car.select { |c|
|
|
48
|
+
c.join(Car_Features).on(Car.id == Car_Features.car_id) { |cc|
|
|
49
|
+
cc.where(:name.ilike('ford%') & :color.is('red'))
|
|
50
|
+
}
|
|
51
|
+
}.first
|
|
52
|
+
res.color.should == 'red'
|
|
53
|
+
res.name.should == 'fordmondeo'
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "allows selecting skalar values, e.g. for aggregate functions" do
|
|
58
|
+
most_recent_car = false
|
|
59
|
+
3.times {
|
|
60
|
+
most_recent_car = Car.create(car_create_values(:name => "The Car" ))
|
|
61
|
+
}
|
|
62
|
+
values = Car.select_values('count(*), max(car.id)') { |c|
|
|
63
|
+
c.where(true)
|
|
64
|
+
}.first
|
|
65
|
+
|
|
66
|
+
values[0].to_i.should == 3
|
|
67
|
+
values[1].to_i.should == most_recent_car.id
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "provides convenience methods for selecting skalar values" do
|
|
71
|
+
most_recent_car = false
|
|
72
|
+
id_sum = 0
|
|
73
|
+
3.times {
|
|
74
|
+
most_recent_car = Car.create(car_create_values(:name => "The Car" ))
|
|
75
|
+
id_sum += most_recent_car.id
|
|
76
|
+
}
|
|
77
|
+
Car.value_of.max(Car.id).to_i.should == most_recent_car.id
|
|
78
|
+
Car.value_of.sum(Car.id).to_i.should == id_sum
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "does not trigger queries immediately, but provides proxy query objects" do
|
|
82
|
+
Lore::Connection.reset_query_count
|
|
83
|
+
query = Car.select { |c|
|
|
84
|
+
c.where(c.num_seats >= 100)
|
|
85
|
+
c.limit(10,5)
|
|
86
|
+
}
|
|
87
|
+
query.is_a?(Lore::Select_Query).should == true
|
|
88
|
+
query_string = query.sql
|
|
89
|
+
expected = "SELECT * FROM public.car
|
|
90
|
+
JOIN public.car_type ON (public.car_type.car_type_id = public.car.car_type_id)
|
|
91
|
+
JOIN public.motorized ON (public.motorized.id = public.car.motorized_id)
|
|
92
|
+
JOIN public.vehicle ON (public.vehicle.id = public.motorized.vehicle_id)
|
|
93
|
+
JOIN public.motor ON (public.motor.id = public.motorized.motor_id)
|
|
94
|
+
WHERE num_seats >= '100' LIMIT 10 OFFSET 5"
|
|
95
|
+
query.sql.gsub(/\s/,'').should == expected.gsub(/\s/,'')
|
|
96
|
+
Lore::Connection.query_count.should == 0
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
|