keso 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,151 @@
1
+
2
+ require 'set'
3
+
4
+ class ImmutableSet
5
+
6
+ def initialize(*args)
7
+
8
+ @set = Set.new;
9
+
10
+ args.each do |value|
11
+ if value.is_a? ImmutableSet
12
+ @set.merge value.set
13
+ elsif value.is_a? Set
14
+ @set.merge value
15
+ elsif value.is_a? Array
16
+ @set.merge value
17
+ elsif not value.nil?
18
+ @set.add value
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ def size
25
+ @set.size
26
+ end
27
+
28
+ alias :count :size
29
+
30
+ def each &block
31
+ @set.to_a.each do |value|
32
+ block.call value
33
+ end
34
+ end
35
+
36
+ def add *values
37
+
38
+ new_set = @set.clone
39
+
40
+ values.each do |value|
41
+ if value.is_a? ImmutableSet
42
+ new_set.merge(value.to_a)
43
+ elsif value.is_a? Set
44
+ new_set.merge(value)
45
+ elsif value.is_a? Array
46
+ new_set.merge(value)
47
+ else
48
+ new_set.add(value)
49
+ end
50
+ end
51
+
52
+ ImmutableSet.new(new_set)
53
+ end
54
+
55
+ def hash
56
+ @set.hash
57
+ end
58
+
59
+ def eql? other
60
+ self == other
61
+ end
62
+
63
+ def == other
64
+ if other.equal?(self)
65
+ true
66
+ elsif !self.class.equal?(other.class)
67
+ false
68
+ else
69
+ self.set.eql?(other.set)
70
+ end
71
+ end
72
+
73
+ def delete *values
74
+
75
+ new_set = @set.clone
76
+
77
+ values.each do |value|
78
+ if value.is_a? ImmutableSet
79
+ new_set.subtract(value.to_a)
80
+ elsif value.is_a? Set
81
+ new_set.subtract(value)
82
+ elsif value.is_a? Array
83
+ new_set.subtract(value)
84
+ else
85
+ new_set.delete(value)
86
+ end
87
+ end
88
+
89
+ ImmutableSet.new(new_set)
90
+ end
91
+
92
+ alias :remove :delete
93
+
94
+ def to_a
95
+ @set.to_a
96
+ end
97
+
98
+ def include? value
99
+ @set.include? value
100
+ end
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+ def subset? other_set
109
+ self.set.subset?(other_set.set)
110
+ end
111
+
112
+ def superset? other_set
113
+ self.set.superset?(other_set.set)
114
+ end
115
+
116
+ alias :superset_of? :superset?
117
+
118
+ def proper_subset? other_set
119
+ self.set.proper_subset?(other_set.set)
120
+ end
121
+
122
+ alias :proper_subset_of? :proper_subset?
123
+
124
+ def proper_superset? other_set
125
+ self.set.proper_superset?(other_set.set)
126
+ end
127
+
128
+ alias :proper_superset_of? :proper_superset?
129
+
130
+ def union *values
131
+ self.add *values
132
+ end
133
+
134
+ def complement other_set
135
+ ImmutableSet.new(self.set - other_set.set)
136
+ end
137
+
138
+ def intersect other_set
139
+ ImmutableSet.new(self.set & other_set.set)
140
+ end
141
+
142
+
143
+
144
+ protected
145
+
146
+ def set
147
+ @set
148
+ end
149
+
150
+ end
151
+
@@ -0,0 +1,455 @@
1
+
2
+ #
3
+ # Subset,Superset
4
+ #
5
+ # Union, Intersection, Complement, Cartesian, join
6
+ # natrual_join: Joins two relations based on all common parts of there headers
7
+ #
8
+
9
+
10
+ #
11
+ # Ref
12
+ #
13
+ # http://en.wikipedia.org/wiki/Set_%28mathematics%29
14
+ # http://en.wikipedia.org/wiki/Relational_algebra
15
+ #
16
+ # Set methods
17
+ #
18
+ # r1.subset(r2) # boolean result
19
+ # r1.proper_subset(r2) # boolean result
20
+ # r1.superset(r2) # boolean result
21
+ # r1.proper_superset(r2) # boolean result
22
+ # r1.union(r2) # r1 + r2, set result
23
+ # r1.intersect(r2) # all in r1 that is also in r2, set result
24
+ # r1.complement(r2) # r1 - r2, set result
25
+
26
+
27
+
28
+ #
29
+ # Relational methods
30
+ #
31
+ # r1.project('Name','age') # results in a relation of only the supplied attributes, set result
32
+ # r1.project_all_but('Name','age') # results in a relation with all attributes exepct the supplied ones, set result
33
+ # r1.rename('Name','PersonName') # changes the attribute name from "Name" to "PersonName", set result
34
+ # r1.select('age' >= 18) # results in a raltion with where ('age' >= 18) is true, set result
35
+ # r1.join(r2) do |tupel| ... end
36
+ # r1.cartesian_product(r2) # new relation with r1 * r2 tuples with all attributes of r1 and r2, set result
37
+ # r1.natrual_join(r2) # cartesian_product with a selection based on equal attributes having to have equal value, set result
38
+ # r1.group
39
+ # r1.ungroup
40
+ # r1.summarize(:name) do |tuples,new_tuple|
41
+ # new_tuple.add('avrange_age',avg(tuples,'age'))
42
+ # new_tuple.add('max_age',max(tuples,'age'))
43
+ # new_tuple.add('min_age',min(tuples,'age'))
44
+ # new_tuple.add('median_age',median(tuples,'age'))
45
+ # end
46
+
47
+ #
48
+ # Add a to_keso to active record and also create a gem
49
+ #
50
+
51
+ # Tutorial D
52
+ #
53
+ # r1.project('Name','Age').group(['Age'],'Names') # results in a new relation as r{'Age' => integer, 'Names' => r{'Name' => String}}
54
+ # r1.project('Name','Age').group(['Age'],'Names').ungroup('Names'[,{'Name' => 'New_name'}]) # results in a new relation as r{'Age' => integer, 'Name' => String}
55
+ #
56
+
57
+ # A relation is a set of tupels constrainted to what can be described as a relational type by a heading, this means that
58
+ # the relation only takes tuples with the same heading as the relation.
59
+ # It has a body
60
+ # It has a heading
61
+ #
62
+ # All parts of the body must of the heading
63
+ #
64
+ #
65
+ #
66
+ #
67
+ #
68
+
69
+ class Relation
70
+
71
+ attr_reader :body, :heading
72
+
73
+ def initialize *value
74
+ value = value[0]
75
+ if value.is_a? Tuple
76
+ @heading = value.heading
77
+ @body = ImmutableSet.new value
78
+ elsif value.is_a? Heading
79
+ @heading = value
80
+ @body = ImmutableSet.new
81
+ elsif value.is_a? Relation
82
+ @heading = value.heading
83
+ @body = value.body
84
+ elsif value.is_a? Hash
85
+ @heading = Heading.new value
86
+ @body = ImmutableSet.new
87
+ elsif value.nil?
88
+ # oo... so you want an empty relation ?
89
+ @heading = Heading.new
90
+ @body = ImmutableSet.new
91
+ else
92
+ raise "Only accept Tuple,Heading,Relation or Hash types"
93
+ end
94
+ end
95
+
96
+ def add tuple
97
+ if tuple.is_a? Tuple
98
+ if tuple.heading == @heading
99
+ Relation.new(@heading).set_body(@body.add tuple)
100
+ else
101
+ throw 'its not of the same heading!'+", #{tuple.heading.inspect} != #{@heading.inspect}"
102
+ end
103
+ else
104
+ throw "Only tuples are supported"
105
+ end
106
+ end
107
+
108
+ def subset_of? other_relation
109
+ @body.subset? other_relation.get_body
110
+ end
111
+
112
+ def proper_subset_of? other_relation
113
+ @body.proper_subset_of? other_relation.get_body
114
+ end
115
+
116
+ def superset_of? other_relation
117
+ @body.superset_of? other_relation.get_body
118
+ end
119
+
120
+ def proper_superset_of? other_relation
121
+ @body.proper_superset_of? other_relation.get_body
122
+ end
123
+
124
+ def union other_relation
125
+ if self.heading == other_relation.heading
126
+ new_body = self.get_body.union(other_relation.get_body)
127
+ new_relation = Relation.new self.heading
128
+ new_relation.set_body new_body
129
+ return new_relation
130
+ else
131
+ throw "Not of the same heading"
132
+ end
133
+ end
134
+
135
+ def intersect other_relation
136
+ if self.heading == other_relation.heading
137
+ new_body = self.get_body.intersect other_relation.get_body
138
+ new_relation = Relation.new self.heading
139
+ new_relation.set_body new_body
140
+ return new_relation
141
+ else
142
+ throw "Not of the same heading"
143
+ end
144
+ end
145
+
146
+ def complement other_relation
147
+ if self.heading == other_relation.heading
148
+ new_body = self.get_body.complement other_relation.get_body
149
+ new_relation = Relation.new self.heading
150
+ new_relation.set_body new_body
151
+ return new_relation
152
+ else
153
+ throw "Not of the same heading"
154
+ end
155
+ end
156
+
157
+
158
+
159
+ def project *args
160
+
161
+ new_heading = Heading.new
162
+
163
+ args.each do |symbol|
164
+ if self.heading[symbol].nil?
165
+ throw "no attribute with the name #{symbol}"
166
+ end
167
+
168
+ new_heading = new_heading.add(self.heading[symbol])
169
+ end
170
+
171
+ if new_heading.count == 0
172
+ return Relation.new new_heading
173
+ end
174
+
175
+ new_relation = Relation.new new_heading
176
+ @body.each do |tuple|
177
+ new_tuple = Tuple.new
178
+
179
+ args.each do |symbol|
180
+ new_tuple = new_tuple.add(symbol => tuple[symbol])
181
+ end
182
+
183
+ new_relation = new_relation.add new_tuple
184
+ end
185
+
186
+
187
+
188
+ return new_relation
189
+ end
190
+
191
+ def project_all_but *args
192
+
193
+ new_heading = Heading.new self.heading
194
+
195
+ args.each do |symbol|
196
+ if self.heading[symbol].nil?
197
+ throw "no attribute with the name #{symbol}"
198
+ end
199
+
200
+ new_heading = new_heading.remove symbol
201
+ end
202
+
203
+ if new_heading.count == 0
204
+ return Relation.new new_heading
205
+ end
206
+
207
+ new_relation = Relation.new new_heading
208
+ @body.each do |tuple|
209
+ new_tuple = Tuple.new
210
+
211
+ new_heading.each do |attribute|
212
+ new_tuple = new_tuple.add(attribute => tuple[attribute.name])
213
+ end
214
+
215
+ new_relation = new_relation.add new_tuple
216
+ end
217
+
218
+ return new_relation
219
+ end
220
+
221
+ def rename from,to
222
+ new_relation = Relation.new self.heading.rename(from,to)
223
+ self.each do |tuple|
224
+ new_relation = new_relation.add tuple.rename(from,to)
225
+ end
226
+
227
+ new_relation
228
+ end
229
+
230
+
231
+
232
+ def count
233
+ @body.size
234
+ end
235
+
236
+ def size
237
+ self.count
238
+ end
239
+
240
+ def length
241
+ self.count
242
+ end
243
+
244
+ def each &block
245
+ @body.each do |value|
246
+ block.call value
247
+ end
248
+ end
249
+
250
+
251
+ def select &block
252
+ new_relation = Relation.new self.heading
253
+ self.each do |tuple|
254
+ new_relation = new_relation.add(tuple) if block.call(tuple)
255
+ end
256
+
257
+ new_relation
258
+ end
259
+
260
+
261
+ def join other_relation,&block
262
+ new_relation = Relation.new(self.heading.add(other_relation.heading))
263
+ self.each do |tuple|
264
+ other_relation.each do |tuple2|
265
+ tuple3 = tuple.add(tuple2)
266
+ new_relation = new_relation.add(tuple3) if block.call(tuple3)
267
+ end
268
+ end
269
+
270
+ new_relation
271
+ end
272
+
273
+ def cartesian_product other_relation
274
+ self.join other_relation do |tuple|
275
+ true
276
+ end
277
+ end
278
+
279
+ def natrual_join other_relation
280
+
281
+ the_same = []
282
+
283
+ self.heading.each do |attribute|
284
+ other_relation.heading.each do |attribute2|
285
+ if attribute == attribute2
286
+ the_same.push attribute
287
+ end
288
+ end
289
+ end
290
+
291
+ old_and_new_name = {}
292
+ the_same.each do |value|
293
+ other_relation = other_relation.rename(value.name,value.name+"_2")
294
+ old_and_new_name[value.name] = value.name+"_2"
295
+ end
296
+
297
+ to_return = self.join(other_relation) do |tuple|
298
+
299
+ r = true
300
+
301
+ old_and_new_name.each do |name,name2|
302
+ unless tuple[name] == tuple[name2]
303
+ r = false
304
+ end
305
+ end
306
+
307
+ r
308
+ end
309
+
310
+
311
+ to_return = to_return.project_all_but *(old_and_new_name.values)
312
+
313
+ to_return
314
+ end
315
+
316
+
317
+ def summarize column_names, &block
318
+
319
+ column_names = [column_names] unless column_names.is_a? Array
320
+
321
+ new_tuples = []
322
+
323
+ self.group(column_names,"temp_12345").each do |tuple|
324
+ new_tuples.push(block.call(tuple.remove("temp_12345"),tuple['temp_12345']))
325
+ end
326
+
327
+ to_return = Relation.new new_tuples.first.heading
328
+
329
+ new_tuples.each do |tuple|
330
+ to_return = to_return.add tuple
331
+ end
332
+
333
+ to_return
334
+ end
335
+
336
+
337
+ def ungroup column_name
338
+
339
+ new_tuples = []
340
+ self.each do |tuple|
341
+ inner_relation = tuple[column_name]
342
+ tuple = tuple.remove column_name
343
+ inner_relation.each do |inner_tuple|
344
+ temp = tuple
345
+ inner_tuple.each do |attribute,value|
346
+ temp = temp.add({attribute => value})
347
+ new_tuples.push(temp)
348
+ end
349
+ end
350
+ end
351
+
352
+ new_heading = self.heading.remove column_name
353
+ self.heading[column_name].type.each do |attribute|
354
+ new_heading = new_heading.add attribute
355
+ end
356
+
357
+ to_return = Relation.new new_heading
358
+ new_tuples.each do |tuple|
359
+ to_return = to_return.add tuple
360
+ end
361
+
362
+ to_return
363
+ end
364
+
365
+ def group column_names,new_column_name
366
+
367
+ # create the headings
368
+ new_heading = Heading.new
369
+ new_inner_heading = self.heading
370
+
371
+ column_names.each do |column_name|
372
+ throw "there is no #{column_name} in [#{self.heading.names.join(',')}]" if self.heading[column_name].nil?
373
+ new_heading = new_heading.add self.heading[column_name]
374
+ end
375
+
376
+ column_names.each do |column_name|
377
+ new_inner_heading = new_inner_heading.remove column_name
378
+ end
379
+
380
+ new_heading = new_heading.add(:name => new_column_name, :type => new_inner_heading)
381
+
382
+ # split the data
383
+ temp_data = {}
384
+
385
+ self.each do |tuple|
386
+ new_tuple = Tuple.new
387
+ new_inner_tuple = Tuple.new
388
+
389
+ new_heading.each do |attribute|
390
+ new_tuple = new_tuple.add(attribute => tuple[attribute]) unless attribute.name.to_s == new_column_name.to_s
391
+ end
392
+
393
+ new_inner_heading.each do |attribute|
394
+ new_inner_tuple = new_inner_tuple.add(attribute => tuple[attribute])
395
+ end
396
+
397
+ temp_data[new_tuple] ||= []
398
+ temp_data[new_tuple].push new_inner_tuple
399
+ end
400
+
401
+
402
+ # create the new realation
403
+ new_relation = Relation.new new_heading
404
+
405
+ temp_data.each do |tuple,array_of_tuples|
406
+
407
+ inner_relation = Relation.new new_inner_heading
408
+
409
+ array_of_tuples.each do |inner_tuple|
410
+ inner_relation = inner_relation.add(inner_tuple)
411
+ end
412
+
413
+ tuple = tuple.add(new_column_name => inner_relation)
414
+ new_relation = new_relation.add(tuple)
415
+ end
416
+
417
+ new_relation
418
+ end
419
+
420
+ def eql? other
421
+ self == other
422
+ end
423
+
424
+ def == other
425
+ if other.equal?(self)
426
+ true
427
+ elsif !self.class.equal?(other.class)
428
+ false
429
+ else
430
+ self.get_body.eql?(other.get_body)
431
+ end
432
+ end
433
+
434
+ def hash
435
+ self.get_body.hash
436
+ end
437
+
438
+ protected
439
+
440
+ def set_body body
441
+ @body = body
442
+ self
443
+ end
444
+
445
+ def get_body
446
+ @body
447
+ end
448
+
449
+
450
+ end
451
+
452
+
453
+
454
+
455
+