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.
Files changed (111) hide show
  1. data/Manifest.txt +16 -7
  2. data/README.rdoc +91 -0
  3. data/benchmark/benchmark.sql +11 -0
  4. data/benchmark/results.txt +28 -0
  5. data/benchmark/select.rb +352 -0
  6. data/lib/lore.rb +22 -8
  7. data/lib/lore/adapters/context.rb +64 -0
  8. data/lib/lore/adapters/postgres-pr.rb +6 -0
  9. data/lib/lore/adapters/postgres-pr/connection.rb +93 -0
  10. data/lib/lore/adapters/postgres-pr/result.rb +63 -0
  11. data/lib/lore/{types.rb → adapters/postgres-pr/types.rb} +36 -0
  12. data/lib/lore/adapters/postgres.rb +24 -0
  13. data/lib/lore/adapters/postgres/connection.rb +81 -0
  14. data/lib/lore/adapters/postgres/result.rb +82 -0
  15. data/lib/lore/adapters/postgres/types.rb +91 -0
  16. data/lib/lore/bits.rb +18 -0
  17. data/lib/lore/cache/abstract_entity_cache.rb +2 -1
  18. data/lib/lore/cache/cacheable.rb +12 -177
  19. data/lib/lore/cache/memcache_entity_cache.rb +89 -0
  20. data/lib/lore/cache/memory_entity_cache.rb +77 -0
  21. data/lib/lore/cache/mmap_entity_cache.rb +2 -2
  22. data/lib/lore/cache/mmap_entity_cache_bork.rb +86 -0
  23. data/lib/lore/clause.rb +107 -35
  24. data/lib/lore/{exception → exceptions}/ambiguous_attribute.rb +2 -2
  25. data/lib/lore/{exception → exceptions}/cache_exception.rb +1 -1
  26. data/lib/lore/exceptions/database_exception.rb +16 -0
  27. data/lib/lore/{exception/invalid_parameter.rb → exceptions/invalid_field.rb} +7 -4
  28. data/lib/lore/exceptions/unknown_type.rb +18 -0
  29. data/lib/lore/exceptions/validation_failure.rb +71 -0
  30. data/lib/lore/gui/form_generator.rb +109 -60
  31. data/lib/lore/gui/lore_model_select_field.rb +1 -0
  32. data/lib/lore/migration.rb +84 -25
  33. data/lib/lore/model.rb +3 -18
  34. data/lib/lore/{aspect.rb → model/aspect.rb} +0 -0
  35. data/lib/lore/model/associations.rb +225 -0
  36. data/lib/lore/model/attribute_settings.rb +233 -0
  37. data/lib/lore/model/filters.rb +34 -0
  38. data/lib/lore/model/mockable.rb +62 -0
  39. data/lib/lore/{model_factory.rb → model/model_factory.rb} +68 -39
  40. data/lib/lore/model/model_instance.rb +382 -0
  41. data/lib/lore/{model_shortcuts.rb → model/model_shortcuts.rb} +7 -0
  42. data/lib/lore/model/polymorphic.rb +53 -0
  43. data/lib/lore/model/prepare.rb +97 -0
  44. data/lib/lore/model/table_accessor.rb +1016 -0
  45. data/lib/lore/query.rb +71 -0
  46. data/lib/lore/query_shortcuts.rb +43 -11
  47. data/lib/lore/strategies/table_delete.rb +115 -0
  48. data/lib/lore/strategies/table_insert.rb +146 -0
  49. data/lib/lore/strategies/table_select.rb +299 -0
  50. data/lib/lore/strategies/table_update.rb +155 -0
  51. data/lib/lore/validation/parameter_validator.rb +85 -26
  52. data/lib/lore/validation/type_validator.rb +34 -78
  53. data/{custom_models.rb → lore-0.9.2.gem} +0 -0
  54. data/lore.gemspec +26 -17
  55. data/spec/clause.rb +37 -0
  56. data/spec/fixtures/blank_models.rb +37 -0
  57. data/{test/model.rb → spec/fixtures/models.rb} +64 -41
  58. data/spec/fixtures/polymorphic_models.rb +68 -0
  59. data/spec/model_associations.rb +86 -0
  60. data/spec/model_create.rb +47 -0
  61. data/spec/model_definition.rb +151 -0
  62. data/spec/model_delete.rb +31 -0
  63. data/spec/model_inheritance.rb +50 -0
  64. data/spec/model_polymorphic.rb +85 -0
  65. data/spec/model_select.rb +101 -0
  66. data/spec/model_select_eager.rb +42 -0
  67. data/spec/model_union_select.rb +33 -0
  68. data/spec/model_update.rb +45 -0
  69. data/spec/model_validation.rb +20 -0
  70. data/spec/spec_db.sql +808 -0
  71. data/spec/spec_env.rb +19 -0
  72. data/spec/spec_helpers.rb +77 -0
  73. metadata +93 -82
  74. data/lib/lore/README.txt +0 -84
  75. data/lib/lore/behaviours/lockable.rb +0 -55
  76. data/lib/lore/behaviours/movable.rb +0 -72
  77. data/lib/lore/behaviours/paginated.rb +0 -31
  78. data/lib/lore/behaviours/versioned.rb +0 -36
  79. data/lib/lore/connection.rb +0 -152
  80. data/lib/lore/exception/invalid_klass_parameters.rb +0 -63
  81. data/lib/lore/exception/unknown_typecode.rb +0 -19
  82. data/lib/lore/result.rb +0 -119
  83. data/lib/lore/symbol.rb +0 -58
  84. data/lib/lore/table_accessor.rb +0 -1790
  85. data/lib/lore/table_deleter.rb +0 -116
  86. data/lib/lore/table_inserter.rb +0 -170
  87. data/lib/lore/table_instance.rb +0 -389
  88. data/lib/lore/table_selector.rb +0 -285
  89. data/lib/lore/table_updater.rb +0 -157
  90. data/lib/lore/validation.rb +0 -65
  91. data/lib/lore/validation/message.rb +0 -60
  92. data/lib/lore/validation/reason.rb +0 -52
  93. data/lore_test.log +0 -2366
  94. data/test/README +0 -31
  95. data/test/custom_models.rb +0 -18
  96. data/test/env.rb +0 -5
  97. data/test/prepare.rb +0 -37
  98. data/test/tc_aspect.rb +0 -58
  99. data/test/tc_cache.rb +0 -83
  100. data/test/tc_clause.rb +0 -104
  101. data/test/tc_deep_inheritance.rb +0 -49
  102. data/test/tc_factory.rb +0 -57
  103. data/test/tc_filter.rb +0 -37
  104. data/test/tc_form.rb +0 -32
  105. data/test/tc_model.rb +0 -140
  106. data/test/tc_prepare.rb +0 -44
  107. data/test/tc_refined_query.rb +0 -88
  108. data/test/tc_table_accessor.rb +0 -267
  109. data/test/tc_thread.rb +0 -100
  110. data/test/test_db.sql +0 -400
  111. data/test/test_lore.rb +0 -50
File without changes
@@ -9,37 +9,46 @@ spec = Gem::Specification.new { |s|
9
9
  s.description = <<-EOF
10
10
  Lore is an object-relational mapping (ORM) implementation
11
11
  providing many features like prepared statements,
12
- (multiple) inheritance, a comfortable query syntax,
13
- highly customizable automated form generation,
14
- and result caching using memory mapping (MMap).
12
+ (multiple) inheritance, true polymorphism, a comfortable
13
+ query syntax, highly customizable automated form generation,
14
+ and result caching.
15
15
  It aims at performance, usability and - unlike most ORMs -
16
- high coverage of native SQL functions and features.
16
+ high coverage of object oriented paradigms.
17
17
  Lore is currently using PostgreSQL as database backend.
18
18
  EOF
19
- s.version = '0.4.8'
20
- s.author = 'Tobias Fuchs'
21
- s.email = 'fuchs@atomnode.net'
22
- s.date = Time.now
23
- s.files = '*.rb'
24
- s.add_dependency('postgres', '>= 0.1')
25
- s.add_dependency('aurita-gui', '>= 0.1')
19
+ s.version = '0.9.2'
20
+ s.author = 'Tobias Fuchs'
21
+ s.email = 'twh.fuchs@gmail.com'
22
+ s.date = Time.now
23
+ s.files = '*.rb'
24
+
25
+ s.requirements = "A ruby binding for PostgreSQL, such as postgres or postgres-pr. "
26
+ # Remove dependency as postgres-pr would be ok, too
27
+ # s.add_dependency('postgres', '>= 0.1')
28
+ s.add_dependency('aurita-gui', '>= 0.2')
26
29
  s.files = FileList['*',
30
+ 'benchmark/*',
31
+ 'spec/*',
32
+ 'spec/fixtures/*',
27
33
  'lib/*',
28
34
  'lib/lore/*',
29
- 'lib/lore/behaviours/*',
35
+ 'lib/lore/adapters/*',
36
+ 'lib/lore/adapters/postgres/*',
37
+ 'lib/lore/adapters/postgres-pr/*',
30
38
  'lib/lore/cache/*',
31
- 'lib/lore/validation/*',
39
+ 'lib/lore/exceptions/*',
32
40
  'lib/lore/gui/*',
33
41
  'lib/lore/gui/templates/*',
34
- 'lib/lore/exception/*',
35
- 'bin/*',
36
- 'test/*'].to_a
42
+ 'lib/lore/model/*',
43
+ 'lib/lore/strategies/*',
44
+ 'lib/lore/validation/*',
45
+ 'bin/*'].to_a
37
46
 
38
47
  s.has_rdoc = true
39
48
  s.rdoc_options << '--title' << 'Lore ORM' <<
40
49
  '--main' << 'Lore::Model' <<
41
50
  '--line-numbers'
42
51
 
43
- s.homepage = 'http://lore.rubyforge.org'
52
+ s.homepage = 'http://github.com/fuchsto/lore/'
44
53
 
45
54
  }
@@ -0,0 +1,37 @@
1
+
2
+ require 'spec_env'
3
+
4
+ include Lore::Spec_Fixtures::Models
5
+
6
+ describe(Lore::Clause) do
7
+
8
+ it "is assigned to a concrete table field" do
9
+ Car.maxspeed.to_s.should == 'public.vehicle.maxspeed'
10
+ Car.num_seats.to_s.should == 'public.vehicle.num_seats'
11
+ Car.num_doors.to_s.should == 'public.car.num_doors'
12
+ Car.name.to_s.should == 'public.vehicle.name'
13
+ # should agggregates be included?
14
+ # Car.type_name.to_s.should == 'public.car_type.type_name
15
+ end
16
+
17
+ it "has comparison operators like >, <, <=>, <=, >= and some aliases" do
18
+ (Car.maxspeed > 100).to_s.should == "public.vehicle.maxspeed > '100'"
19
+ (Car.num_doors == 4).to_s.should == "public.car.num_doors = '4'"
20
+ (Car.num_seats <= 5).to_s.should == "public.vehicle.num_seats <= '5'"
21
+ end
22
+
23
+ it "has special SQL comparison operators such as between, like, ilike" do
24
+ Car.name.like('%wombat').to_s.should == "public.vehicle.name LIKE '%wombat'"
25
+ end
26
+
27
+ it "has logical operators like & and |" do
28
+ clause = Car.name.ilike('%knurt%').and(Car.num_doors.is(3))
29
+ clause.to_sql.should == "(public.vehicle.name ILIKE '%knurt%' AND public.car.num_doors = '3')"
30
+
31
+ or_clause = (Vehicle.num_seats.in(1..5))
32
+ or_clause.to_sql.should == "public.vehicle.num_seats BETWEEN 1 AND 5 "
33
+
34
+ (clause | or_clause).to_sql.should == "((public.vehicle.name ILIKE '%knurt%' AND public.car.num_doors = '3') OR public.vehicle.num_seats BETWEEN 1 AND 5 )"
35
+ end
36
+
37
+ end
@@ -0,0 +1,37 @@
1
+
2
+ module Lore
3
+ module Spec_Fixtures
4
+ module Blank_Models
5
+
6
+ NAME_FORMAT = { :format => /^([a-zA-Z_0-9 ])+$/, :length => 3..100, :mandatory => true }
7
+
8
+ class Vehicle < Lore::Model
9
+ end
10
+
11
+ class Motor < Lore::Model
12
+ end
13
+
14
+ class Motorized_Vehicle < Lore::Model
15
+ end
16
+
17
+ class Car < Vehicle
18
+ end
19
+
20
+ class Motorbike < Vehicle
21
+ end
22
+
23
+ class Owner < Lore::Model
24
+ end
25
+
26
+ class Vehicle_Owner < Lore::Model
27
+ end
28
+
29
+ class Car_Type < Lore::Model
30
+ end
31
+
32
+ class Garage < Lore::Model
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -1,33 +1,28 @@
1
1
 
2
2
  require 'rubygems'
3
- require('./test/env')
3
+ require('lore')
4
4
  require('lore/model')
5
5
 
6
- Lore::Context.enter :test
7
-
8
6
  module Lore
9
- module Unit
7
+ module Spec_Fixtures
8
+ module Models
10
9
 
11
- NAME_FORMAT = { :format => /^([a-zA-Z_0-9])+$/, :length => 3..100, :mandatory => true }
10
+ NAME_FORMAT = { :format => /^([a-zA-Z_0-9 ])+$/, :length => 3..100, :mandatory => true }
12
11
 
13
12
  class Manufacturer < Lore::Model
14
13
  table :manufacturer, :public
15
14
  primary_key :manuf_id, :manuf_id_seq
16
15
 
17
- validates :name, NAME_FORMAT
16
+ # validates :name, NAME_FORMAT
18
17
 
19
18
  use_label :name
20
-
21
- cache_entities
22
19
  end
23
20
 
24
21
  class Owner < Lore::Model
25
22
  table :owner, :public
26
23
  primary_key :owner_id, :owner_id_seq
27
24
 
28
- validates :name, NAME_FORMAT
29
-
30
- cache_entities
25
+ # validates :name, NAME_FORMAT
31
26
  end
32
27
 
33
28
  class Vehicle < Lore::Model
@@ -37,21 +32,17 @@ module Unit
37
32
  has_a Manufacturer, :manuf_id
38
33
  has_n Owner, :vehicle_id
39
34
 
40
- validates :name, NAME_FORMAT
35
+ # validates :name, NAME_FORMAT
41
36
  validates :maxspeed, :mandatory => true
42
37
  validates :num_seats, :mandatory => true
43
38
 
44
39
  add_input_filter(:name) { |name|
45
40
  name.gsub(/[^a-zA-Z_0-9]/,'').downcase
46
41
  }
47
- add_input_filter(:maxspeed) { |m| m.to_s.gsub('km/h','') }
42
+ add_input_filter(:maxspeed) { |m| m.to_s.sub('km/h','') }
48
43
  add_output_filter(:maxspeed) { |m| m << 'km/h' }
49
44
 
50
- explicit :optional, :owner_id
51
-
52
45
  # add_select_filter { |clause| clause & (Vehicle.deleted == 't') }
53
-
54
- cache_entities
55
46
  end
56
47
 
57
48
  class Vehicle_Owner < Lore::Model
@@ -71,27 +62,55 @@ module Unit
71
62
  table :car_type, :public
72
63
  primary_key :car_type_id, :car_type_id_seq
73
64
 
74
- validates :name, NAME_FORMAT
65
+ # validates :type_name, NAME_FORMAT
75
66
 
76
- use_label :name
67
+ use_label :type_name
68
+ end
77
69
 
78
- cache_entities
70
+ class Motor < Lore::Model
71
+ table :motor, :public
72
+ primary_key :id, :motor_id_seq
73
+
74
+ expects :kw
75
+ end
76
+
77
+ class Motorized_Vehicle < Vehicle
78
+ table :motorized, :public
79
+ primary_key :id, :motorized_id_seq
80
+
81
+ is_a Vehicle, :vehicle_id
82
+ aggregates Motor, :motor_id
79
83
  end
80
84
 
81
- class Car < Vehicle
85
+ class Car < Motorized_Vehicle
82
86
  table :car, :public
83
87
  primary_key :id, :car_id_seq
84
88
 
85
- is_a Vehicle, :vehicle_id
89
+ # This is not a typo: As vehicle_id is a unique,
90
+ # inherited primary key in Motorized_Vehicle, it
91
+ # must be allowed for referencing a Motorized_Vehicle.
92
+ # is_a Motorized_Vehicle, :vehicle_id
93
+ is_a Motorized_Vehicle, :motorized_id
86
94
  aggregates Car_Type, :car_type_id
87
95
 
88
- validates :num_seats, :mandatory => true
96
+ # validates :num_seats, :mandatory => true
89
97
  validates :num_doors, :mandatory => true
90
98
 
91
99
  add_input_filter(:maxspeed) { |m| m.to_s.gsub('km/h','') }
92
100
  add_output_filter(:maxspeed) { |m| m << 'km/h' }
93
101
 
94
- cache_entities
102
+ def drive
103
+ "driving with #{maxspeed}!"
104
+ end
105
+ end
106
+
107
+ class Car_Features < Lore::Model
108
+ table :car_features, :public
109
+ primary_key :id, :car_features_id_seq
110
+
111
+ has_a Car, :car_id
112
+
113
+ expects :color
95
114
  end
96
115
 
97
116
  class Convertible < Car
@@ -107,36 +126,40 @@ module Unit
107
126
  aggregates Car, :car_id
108
127
  end
109
128
 
110
- class Bike < Vehicle
111
- table :bike, :public
112
- primary_key :bike_id, :bike_id_seq
129
+ class Motorbike < Motorized_Vehicle
130
+ table :motorbike, :public
131
+ primary_key :id, :bike_id_seq
113
132
 
114
- is_a Vehicle, :vehicle_id
115
-
116
- cache_entities
133
+ is_a Motorized_Vehicle, :vehicle_id
117
134
  end
118
- =begin
119
- class Trike < Vehicle
120
- table :trike, :public
121
- primary_key :trike_id, :trike_id_seq
122
-
123
- is_a Car, :car_id
124
- is_a Bike, :bike_id
125
135
 
126
- cache_entities
127
- end
128
- =end
129
136
  class Garage < Lore::Model
130
137
  table :garage, :public
131
138
  primary_key :garage_id, :garage_id_seq
132
139
  primary_key :vehicle_id
133
140
 
134
141
  has_n Vehicle, :vehicle_id
142
+ end
143
+
144
+ class Robot < Lore::Model
145
+ table :robot, :public
146
+ primary_key :id, :robot_id_seq
147
+
148
+ def transform
149
+ 'Autobot transformed!'
150
+ end
151
+ end
152
+
153
+ class Autobot < Robot
154
+ table :autobot, :public
155
+ primary_key :id, :autobot_id_seq
135
156
 
136
- cache_entities
157
+ is_a Robot, :robot_id
158
+ is_a Car, :car_id
137
159
  end
138
160
 
139
161
  end
140
162
  end
163
+ end
141
164
 
142
165
 
@@ -0,0 +1,68 @@
1
+
2
+ require 'lore/model'
3
+
4
+ module Lore
5
+ module Spec_Fixtures
6
+ module Polymorphic_Models
7
+
8
+ class Asset < Lore::Model
9
+
10
+ table :asset, :public
11
+ primary_key :asset_id, :asset_id_seq
12
+
13
+ expects :folder, :filename
14
+
15
+ is_polymorphic :model
16
+
17
+ def path
18
+ folder + '/' + filename
19
+ end
20
+ end
21
+
22
+ class Media_Asset_Info < Lore::Model
23
+ table :media_asset_info, :public
24
+ primary_key :id, :media_asset_id_seq
25
+ expects :media_asset_id
26
+ end
27
+
28
+ class Document_Asset_Info < Lore::Model
29
+ table :document_asset_info, :public
30
+ primary_key :id, :document_asset_id_seq
31
+ expects :document_asset_id
32
+ end
33
+
34
+ class Media_Asset < Asset
35
+ table :media_asset, :public
36
+ primary_key :id, :media_asset_id_seq
37
+
38
+ is_a Asset, :asset_id
39
+
40
+ expects :media_type
41
+ aggregates Media_Asset_Info, :info_id
42
+ end
43
+
44
+ # class Movie_Asset < Media_Asset
45
+ # table :movie_asset, :public
46
+ # primary_key :id, :movie_asset_id_seq
47
+ #
48
+ # is_a Media_Asset, :media_asset_id
49
+ #
50
+ # def self.before_create(args)
51
+ # args[:media_type] = 'movie'
52
+ # end
53
+ # end
54
+
55
+ class Document_Asset < Asset
56
+ table :document_asset, :public
57
+ primary_key :id, :document_asset_id_seq
58
+
59
+ is_a Asset, :asset_id
60
+
61
+ expects :doctype
62
+ aggregates Document_Asset_Info, :info_id
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,86 @@
1
+
2
+ require 'spec_env'
3
+ include Lore::Spec_Fixtures::Models
4
+
5
+ describe(Lore::Table_Accessor) do
6
+ before do
7
+ flush_test_data()
8
+ end
9
+
10
+ it "is assigned to a base table" do
11
+ Car.table_name.should == 'public.car'
12
+ Vehicle.table_name.should == 'public.vehicle'
13
+ end
14
+
15
+ it "loads attribute fields automatically as array of symbols" do
16
+ owner = Owner.create(:name => 'Filou')
17
+ manuf_org = Manufacturer.create(:name => 'Ford')
18
+ manuf_new = Manufacturer.create(:name => 'Ford')
19
+ v = Vehicle.create(:name => 'Ford Mondeo',
20
+ :num_seats => 100,
21
+ :maxspeed => 180,
22
+ :manuf_id => manuf_org.pkey,
23
+ :owner_id => owner.pkey)
24
+ v.manufacturer.should == manuf_org
25
+ end
26
+
27
+ it "allows setting entities for 1:1 relations" do
28
+ owner = Owner.create(:name => 'Filou')
29
+ manuf_org = Manufacturer.create(:name => 'Ford')
30
+ manuf_new = Manufacturer.create(:name => 'Ford')
31
+ motor = Motor.create(:motor_name => 'Ford V8', :kw => 120)
32
+ type = Car_Type.create(:type_name => 'Limousine')
33
+ v = Car.create(:name => 'Ford Mondeo',
34
+ :motor_id => motor.pkey,
35
+ :num_doors => 3,
36
+ :num_seats => 100,
37
+ :maxspeed => 180,
38
+ :car_type_id => type.pkey,
39
+ :manuf_id => manuf_org.pkey,
40
+ :owner_id => owner.pkey)
41
+ v.manufacturer.should == manuf_org
42
+ v.manufacturer = manuf_new
43
+
44
+ expected = { 'public.vehicle' => { :id => v.vehicle_id },
45
+ 'public.car' => { :id => v.id },
46
+ 'public.motorized' => { :id => v.motorized_id } }
47
+
48
+ v.get_primary_key_value_map.should_be expected
49
+ v.commit
50
+ v.manufacturer.should == manuf_new
51
+
52
+ v.set_manufacturer!(manuf_org)
53
+ v.manufacturer.should == manuf_org
54
+ end
55
+
56
+ it "provides 1:n associations" do
57
+ # TODO: Implement this
58
+ #
59
+ # garage = Garage.create()
60
+ # vehicle_1 = Vehicle.create()
61
+ # vehicle_2 = Vehicle.create()
62
+ # car_1 = Car.create()
63
+ # car_2 = Car.create()
64
+ #
65
+ # garage.add_vehicle(vehicle_1)
66
+ # garage.add_vehicle(car_1)
67
+ # garage.save
68
+ # expected = [ vehicle_1, car_1 ]
69
+ # garage.vehicle_set.should_be expected
70
+ #
71
+ # garage.vehicle_set = [ vehicle_2, car_2 ]
72
+ # garage.save
73
+ # expected = [ vehicle_2, car_2 ]
74
+ # garage.vehicle_set.should_be expected
75
+ #
76
+ # garage.vehicle_set.delete(car2)
77
+ # garage.save
78
+ # expected = [ vehicle_2 ]
79
+ # garage.vehicle_set.should_be expected
80
+ end
81
+
82
+ it "provides n:n associations" do
83
+
84
+ end
85
+
86
+ end