Class: Relation

Inherits:
Object
  • Object
show all
Defined in:
lib/values/relation.rb

Overview

A relation is a set of tupels constrainted to what can be described as a relational type by a heading, this means that the relation only takes tuples with the same heading as the relation.

It has a body
It has a heading

All parts of the body must of the heading

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*value) ⇒ Relation

Returns a new instance of Relation.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/values/relation.rb', line 73

def initialize *value
  value = value[0]
  if value.is_a? Tuple
    @heading = value.heading
    @body = ImmutableSet.new value
  elsif value.is_a? Heading
    @heading = value
    @body = ImmutableSet.new
  elsif value.is_a? Relation
    @heading = value.heading
    @body = value.body
  elsif value.is_a? Hash
    @heading = Heading.new value
    @body = ImmutableSet.new
  elsif value.nil?
    # oo... so you want an empty relation ?
    @heading = Heading.new
    @body = ImmutableSet.new
  else
    raise "Only accept Tuple,Heading,Relation or Hash types"
  end
end

Instance Attribute Details

#bodyObject (readonly)

Returns the value of attribute body.



71
72
73
# File 'lib/values/relation.rb', line 71

def body
  @body
end

#headingObject (readonly)

Returns the value of attribute heading.



71
72
73
# File 'lib/values/relation.rb', line 71

def heading
  @heading
end

Instance Method Details

#==(other) ⇒ Object



432
433
434
435
436
437
438
439
440
# File 'lib/values/relation.rb', line 432

def == other
  if other.equal?(self)
    true
  elsif !self.class.equal?(other.class)
    false
  else
    self.get_body.eql?(other.get_body)
  end
end

#add(tuple) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/values/relation.rb', line 96

def add tuple
  if tuple.is_a? Tuple
    if tuple.heading == @heading
      Relation.new(@heading).set_body(@body.add tuple)
    else
      throw 'its not of the same heading!'+", #{tuple.heading.inspect} != #{@heading.inspect}"
    end
  elsif tuple.is_a?(Array) && tuple.first.is_a?(Tuple)
    # Check that all tuples are valid
    tuple.each do |t| 
      if t.heading != @heading
        throw 'its not of the same heading!'+", #{t.heading.inspect} != #{@heading.inspect}"
      end
    end
    Relation.new(@heading).set_body(@body.add tuple)
  else
    throw "Only tuples are supported"
  end
end

#cartesian_product(other_relation) ⇒ Object



281
282
283
284
285
# File 'lib/values/relation.rb', line 281

def cartesian_product other_relation
  self.join other_relation do |tuple|
    true
  end
end

#complement(other_relation) ⇒ Object



154
155
156
157
158
159
160
161
162
163
# File 'lib/values/relation.rb', line 154

def complement other_relation
  if self.heading == other_relation.heading
    new_body = self.get_body.complement other_relation.get_body
    new_relation = Relation.new self.heading
    new_relation.set_body new_body
    return new_relation
  else
    throw "Not of the same heading"
  end
end

#countObject



240
241
242
# File 'lib/values/relation.rb', line 240

def count
  @body.size
end

#each(&block) ⇒ Object



252
253
254
255
256
# File 'lib/values/relation.rb', line 252

def each &block
  @body.each do |value|
    block.call value
  end
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


428
429
430
# File 'lib/values/relation.rb', line 428

def eql? other
  self == other
end

#group(column_names, new_column_name) ⇒ Object



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# File 'lib/values/relation.rb', line 373

def group column_names,new_column_name
  
  # create the headings
  new_heading = Heading.new
  new_inner_heading = self.heading
  
  column_names.each do |column_name|
    throw "there is no #{column_name} in [#{self.heading.names.join(',')}]" if self.heading[column_name].nil?
    new_heading = new_heading.add self.heading[column_name]
  end
  
  column_names.each do |column_name| 
    new_inner_heading = new_inner_heading.remove column_name
  end
  
  new_heading = new_heading.add(:name => new_column_name, :type => new_inner_heading)
  
  # split the data
  temp_data = {}
  
  self.each do |tuple|
    new_tuple = Tuple.new
    new_inner_tuple = Tuple.new

    new_heading.each do |attribute|
      new_tuple = new_tuple.add(attribute => tuple[attribute]) unless attribute.name.to_s == new_column_name.to_s
    end
    
    new_inner_heading.each do |attribute|
      new_inner_tuple = new_inner_tuple.add(attribute => tuple[attribute])
    end
    
    temp_data[new_tuple] ||= []
    temp_data[new_tuple].push new_inner_tuple
  end
  
  
  # create the new realation
  new_relation = Relation.new new_heading
  
  temp_data.each do |tuple,array_of_tuples| 
    
    inner_relation = Relation.new new_inner_heading
    
    array_of_tuples.each do |inner_tuple| 
      inner_relation = inner_relation.add(inner_tuple)
    end
    
    tuple = tuple.add(new_column_name => inner_relation)
    new_relation = new_relation.add(tuple)
  end
  
  new_relation
end

#hashObject



442
443
444
# File 'lib/values/relation.rb', line 442

def hash
  self.get_body.hash
end

#intersect(other_relation) ⇒ Object



143
144
145
146
147
148
149
150
151
152
# File 'lib/values/relation.rb', line 143

def intersect other_relation
  if self.heading == other_relation.heading
    new_body = self.get_body.intersect other_relation.get_body
    new_relation = Relation.new self.heading
    new_relation.set_body new_body
    return new_relation
  else
    throw "Not of the same heading"
  end
end

#join(other_relation, &block) ⇒ Object



269
270
271
272
273
274
275
276
277
278
279
# File 'lib/values/relation.rb', line 269

def join other_relation,&block
  new_relation = Relation.new(self.heading.add(other_relation.heading))
  self.each do |tuple|
    other_relation.each do |tuple2|
      tuple3 = tuple.add(tuple2)
      new_relation = new_relation.add(tuple3) if block.call(tuple3)
    end
  end
  
  new_relation
end

#lengthObject



248
249
250
# File 'lib/values/relation.rb', line 248

def length
  self.count
end

#natrual_join(other_relation) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/values/relation.rb', line 287

def natrual_join other_relation
  
  the_same = []
  
  self.heading.each do |attribute|
    other_relation.heading.each do |attribute2|
      if attribute == attribute2
        the_same.push attribute
      end
    end
  end
    
  old_and_new_name = {}
  the_same.each do |value|
    other_relation = other_relation.rename(value.name,value.name+"_2")
    old_and_new_name[value.name] = value.name+"_2"
  end  
  
  to_return = self.join(other_relation) do |tuple|
    
    r = true
    
    old_and_new_name.each do |name,name2|
      unless tuple[name] == tuple[name2]
        r = false
      end  
    end
    
    r
  end
  

  to_return = to_return.project_all_but *(old_and_new_name.values)
  
  to_return
end

#project(*args) ⇒ Object



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/values/relation.rb', line 167

def project *args
  
  new_heading = Heading.new
  
  args.each do |symbol|
    if self.heading[symbol].nil?
      throw "no attribute with the name #{symbol}"
    end
    
    new_heading = new_heading.add(self.heading[symbol])
  end
  
  if new_heading.count == 0
    return Relation.new new_heading 
  end
  
  new_relation = Relation.new new_heading
  @body.each do |tuple|
    new_tuple = Tuple.new
    
    args.each do |symbol|
      new_tuple = new_tuple.add(symbol => tuple[symbol])
    end
    
    new_relation = new_relation.add new_tuple
  end
  
  
  
  return new_relation
end

#project_all_but(*args) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/values/relation.rb', line 199

def project_all_but *args
  
  new_heading = Heading.new self.heading
  
  args.each do |symbol|
    if self.heading[symbol].nil?
      throw "no attribute with the name #{symbol}"
    end
    
    new_heading = new_heading.remove symbol
  end
  
  if new_heading.count == 0
    return Relation.new new_heading 
  end
  
  new_relation = Relation.new new_heading
  @body.each do |tuple|
    new_tuple = Tuple.new
    
    new_heading.each do |attribute|
      new_tuple = new_tuple.add(attribute => tuple[attribute.name])
    end
    
    new_relation = new_relation.add new_tuple
  end
  
  return new_relation
end

#proper_subset_of?(other_relation) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/values/relation.rb', line 120

def proper_subset_of? other_relation
  @body.proper_subset_of? other_relation.get_body
end

#proper_superset_of?(other_relation) ⇒ Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/values/relation.rb', line 128

def proper_superset_of? other_relation
  @body.proper_superset_of? other_relation.get_body
end

#rename(from, to) ⇒ Object



229
230
231
232
233
234
235
236
# File 'lib/values/relation.rb', line 229

def rename from,to
  new_relation = Relation.new self.heading.rename(from,to)
  self.each do |tuple|
    new_relation = new_relation.add tuple.rename(from,to)
  end
  
  new_relation
end

#select(&block) ⇒ Object



259
260
261
262
263
264
265
266
# File 'lib/values/relation.rb', line 259

def select &block
  new_relation = Relation.new self.heading
  self.each do |tuple|
    new_relation = new_relation.add(tuple) if block.call(tuple)
  end
  
  new_relation
end

#sizeObject



244
245
246
# File 'lib/values/relation.rb', line 244

def size
  self.count
end

#subset_of?(other_relation) ⇒ Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/values/relation.rb', line 116

def subset_of? other_relation
  @body.subset? other_relation.get_body
end

#summarize(column_names, &block) ⇒ Object



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/values/relation.rb', line 325

def summarize column_names, &block
  
  column_names = [column_names] unless column_names.is_a? Array
  
  new_tuples = []
  
  self.group(column_names,"temp_12345").each do |tuple|
    new_tuples.push(block.call(tuple.remove("temp_12345"),tuple['temp_12345']))
  end
  
  to_return = Relation.new new_tuples.first.heading
  
  new_tuples.each do |tuple|
    to_return = to_return.add tuple
  end
  
  to_return
end

#superset_of?(other_relation) ⇒ Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/values/relation.rb', line 124

def superset_of? other_relation
  @body.superset_of? other_relation.get_body
end

#ungroup(column_name) ⇒ Object



345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/values/relation.rb', line 345

def ungroup column_name
  
  new_tuples = []
  self.each do |tuple|
    inner_relation = tuple[column_name]
    tuple = tuple.remove column_name
    inner_relation.each do |inner_tuple|
      temp = tuple
      inner_tuple.each do |attribute,value|
        temp = temp.add({attribute => value})
        new_tuples.push(temp)
      end
    end
  end
  
  new_heading = self.heading.remove column_name
  self.heading[column_name].type.each do |attribute|
    new_heading = new_heading.add attribute
  end
  
  to_return = Relation.new new_heading
  new_tuples.each do |tuple|
    to_return = to_return.add tuple
  end
  
  to_return
end

#union(other_relation) ⇒ Object



132
133
134
135
136
137
138
139
140
141
# File 'lib/values/relation.rb', line 132

def union other_relation
  if self.heading == other_relation.heading
    new_body = self.get_body.union(other_relation.get_body)
    new_relation = Relation.new self.heading
    new_relation.set_body new_body
    return new_relation
  else
    throw "Not of the same heading"
  end
end