locomotive 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/locomotive.rb +6 -0
- data/lib/locomotive/core_extensions.rb +6 -0
- data/lib/locomotive/core_extensions/array.rb +22 -0
- data/lib/locomotive/core_extensions/class.rb +47 -0
- data/lib/locomotive/core_extensions/hash.rb +7 -0
- data/lib/locomotive/core_extensions/inflector.rb +29 -0
- data/lib/locomotive/core_extensions/module.rb +77 -0
- data/lib/locomotive/core_extensions/symbol.rb +17 -0
- data/lib/locomotive/misc.rb +1 -0
- data/lib/locomotive/misc/type_check.rb +129 -0
- data/lib/locomotive/relational_algebra.rb +8 -0
- data/lib/locomotive/relational_algebra/attributes.rb +171 -0
- data/lib/locomotive/relational_algebra/operators.rb +15 -0
- data/lib/locomotive/relational_algebra/operators/abstraction.rb +2 -0
- data/lib/locomotive/relational_algebra/operators/abstraction/lambda.rb +83 -0
- data/lib/locomotive/relational_algebra/operators/abstraction/variable.rb +65 -0
- data/lib/locomotive/relational_algebra/operators/aggregation.rb +2 -0
- data/lib/locomotive/relational_algebra/operators/aggregation/aggr_builtin.rb +26 -0
- data/lib/locomotive/relational_algebra/operators/aggregation/aggregation.rb +76 -0
- data/lib/locomotive/relational_algebra/operators/basic_operators.rb +144 -0
- data/lib/locomotive/relational_algebra/operators/boolean.rb +4 -0
- data/lib/locomotive/relational_algebra/operators/boolean/and.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/boolean/basic_boolean.rb +66 -0
- data/lib/locomotive/relational_algebra/operators/boolean/not.rb +56 -0
- data/lib/locomotive/relational_algebra/operators/boolean/or.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/builtins.rb +3 -0
- data/lib/locomotive/relational_algebra/operators/builtins/arith_builtin.rb +37 -0
- data/lib/locomotive/relational_algebra/operators/builtins/basic_builtin.rb +20 -0
- data/lib/locomotive/relational_algebra/operators/builtins/function.rb +69 -0
- data/lib/locomotive/relational_algebra/operators/comparisons.rb +6 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/basic_comparison.rb +65 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/equal.rb +13 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/greater.rb +13 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/greater_equal.rb +14 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/less.rb +21 -0
- data/lib/locomotive/relational_algebra/operators/comparisons/less_equal.rb +13 -0
- data/lib/locomotive/relational_algebra/operators/error.rb +1 -0
- data/lib/locomotive/relational_algebra/operators/error/error.rb +52 -0
- data/lib/locomotive/relational_algebra/operators/filter.rb +1 -0
- data/lib/locomotive/relational_algebra/operators/filter/select.rb +50 -0
- data/lib/locomotive/relational_algebra/operators/join.rb +5 -0
- data/lib/locomotive/relational_algebra/operators/join/basic_join.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/join/cross.rb +28 -0
- data/lib/locomotive/relational_algebra/operators/join/equi_join.rb +61 -0
- data/lib/locomotive/relational_algebra/operators/join/predicates.rb +95 -0
- data/lib/locomotive/relational_algebra/operators/join/theta_join.rb +53 -0
- data/lib/locomotive/relational_algebra/operators/projections.rb +2 -0
- data/lib/locomotive/relational_algebra/operators/projections/attach.rb +67 -0
- data/lib/locomotive/relational_algebra/operators/projections/projection.rb +106 -0
- data/lib/locomotive/relational_algebra/operators/ranking.rb +6 -0
- data/lib/locomotive/relational_algebra/operators/ranking/basic_ranking.rb +67 -0
- data/lib/locomotive/relational_algebra/operators/ranking/rank.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/ranking/rank_lists.rb +45 -0
- data/lib/locomotive/relational_algebra/operators/ranking/row_id.rb +24 -0
- data/lib/locomotive/relational_algebra/operators/ranking/row_number.rb +55 -0
- data/lib/locomotive/relational_algebra/operators/ranking/row_rank.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/serialization.rb +2 -0
- data/lib/locomotive/relational_algebra/operators/serialization/basic_serialize.rb +9 -0
- data/lib/locomotive/relational_algebra/operators/serialization/serialize_relation.rb +105 -0
- data/lib/locomotive/relational_algebra/operators/set.rb +4 -0
- data/lib/locomotive/relational_algebra/operators/set/basic_set.rb +24 -0
- data/lib/locomotive/relational_algebra/operators/set/difference.rb +11 -0
- data/lib/locomotive/relational_algebra/operators/set/distinct.rb +35 -0
- data/lib/locomotive/relational_algebra/operators/set/union.rb +11 -0
- data/lib/locomotive/relational_algebra/operators/tables.rb +3 -0
- data/lib/locomotive/relational_algebra/operators/tables/literal_table.rb +95 -0
- data/lib/locomotive/relational_algebra/operators/tables/nil.rb +13 -0
- data/lib/locomotive/relational_algebra/operators/tables/ref_table.rb +75 -0
- data/lib/locomotive/relational_algebra/operators/typeing.rb +1 -0
- data/lib/locomotive/relational_algebra/operators/typeing/cast.rb +59 -0
- data/lib/locomotive/relational_algebra/ordering.rb +30 -0
- data/lib/locomotive/relational_algebra/query_information.rb +666 -0
- data/lib/locomotive/relational_algebra/rel_alg_ast_node.rb +51 -0
- data/lib/locomotive/relational_algebra/rel_alg_exceptions.rb +15 -0
- data/lib/locomotive/relational_algebra/schema.rb +87 -0
- data/lib/locomotive/relational_algebra/types.rb +86 -0
- data/lib/locomotive/tree_helpers.rb +3 -0
- data/lib/locomotive/tree_helpers/annotations.rb +58 -0
- data/lib/locomotive/tree_helpers/ast.rb +99 -0
- data/lib/locomotive/tree_helpers/ast_traversal.rb +43 -0
- data/lib/locomotive/utils.rb +2 -0
- data/lib/locomotive/utils/relalg2xml.rb +239 -0
- data/lib/locomotive/utils/xml.rb +47 -0
- metadata +157 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module Locomotive
|
2
|
+
|
3
|
+
module RelationalAlgebra
|
4
|
+
|
5
|
+
# Represents a Relational Algebra node
|
6
|
+
# Such a node has
|
7
|
+
# * the behaviour of a composite pattern
|
8
|
+
# * and node specific annotations
|
9
|
+
class RelAlgAstNode
|
10
|
+
include AstHelpers::AstNode
|
11
|
+
include AstHelpers::Annotations
|
12
|
+
|
13
|
+
[:project, :attach,
|
14
|
+
:or, :and, :not,
|
15
|
+
:aggr,
|
16
|
+
:select,
|
17
|
+
:difference, :union, :distinct,
|
18
|
+
:cross, :equi_join, :theta_join,
|
19
|
+
:equal, :greater_than,
|
20
|
+
:less_than, :less_equal_than,
|
21
|
+
:row_num, :row_id, :rank, :row_rank,
|
22
|
+
:cast,
|
23
|
+
:error,
|
24
|
+
:serialize_relation].each do |op|
|
25
|
+
define_method(op) do |*args|
|
26
|
+
::Locomotive::RelationalAlgebra.const_get(op.classify).new(self, *args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
[:addition, :subtraction,
|
31
|
+
:multiplication, :division].each do |meth|
|
32
|
+
define_method(meth) do |*args|
|
33
|
+
Function.new(self,
|
34
|
+
::Locomotive::RelationalAlgebra.const_get(meth.classify).instance,
|
35
|
+
*args)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
[:max, :min, :count, :avg, :sum, :all].each do |meth|
|
40
|
+
define_method(meth) do |*args|
|
41
|
+
Aggr.new(self,
|
42
|
+
::Locomotive::RelationalAlgebra.const_get(meth.classify).instance,
|
43
|
+
*args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Locomotive
|
2
|
+
|
3
|
+
module RelationalAlgebra
|
4
|
+
|
5
|
+
class IdError < StandardError; end
|
6
|
+
class AbstractClassError < StandardError; end
|
7
|
+
class Duplicates < StandardError; end
|
8
|
+
class CorruptedSchema < StandardError; end
|
9
|
+
class ITblsNotEqual < StandardError; end
|
10
|
+
|
11
|
+
class ArgumentException < StandardError; end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Locomotive
|
2
|
+
|
3
|
+
module RelationalAlgebra
|
4
|
+
|
5
|
+
#
|
6
|
+
# The Schema contains the attributes
|
7
|
+
# and its associated types.
|
8
|
+
# Each operator of the relational algebra
|
9
|
+
# contains a schema.
|
10
|
+
#
|
11
|
+
class Schema
|
12
|
+
include Locomotive::XML
|
13
|
+
def_node :_schema_, :col
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
attr_accessor :schema
|
18
|
+
def_sig :schema=, { ConstAttribute => [RType] }
|
19
|
+
|
20
|
+
# check if there are duplicates in the schemas
|
21
|
+
def duplicates?(schema)
|
22
|
+
(self.attributes + schema.attributes).length >
|
23
|
+
(self.attributes + schema.attributes).uniq.length
|
24
|
+
end
|
25
|
+
def_sig :duplicates?, Schema
|
26
|
+
|
27
|
+
public
|
28
|
+
|
29
|
+
delegate :[],
|
30
|
+
:each,
|
31
|
+
:to => :schema
|
32
|
+
|
33
|
+
def initialize(hash)
|
34
|
+
self.schema = hash
|
35
|
+
end
|
36
|
+
|
37
|
+
def attributes
|
38
|
+
schema.keys
|
39
|
+
end
|
40
|
+
|
41
|
+
def attributes?(attributes)
|
42
|
+
attributes.all? { |attr| self.attributes.member? attr }
|
43
|
+
end
|
44
|
+
def_sig :attributes?, [ConstAttribute]
|
45
|
+
|
46
|
+
# merges two schemas, given that there are
|
47
|
+
# no duplicate keys
|
48
|
+
def +(schm)
|
49
|
+
if duplicates?(schm)
|
50
|
+
raise Duplicates,
|
51
|
+
"Found duplicates in #{self.attributes} " \
|
52
|
+
"and #{schm.attributes}."
|
53
|
+
end
|
54
|
+
# create a new schema
|
55
|
+
Schema.new(schema.merge(schm.schema))
|
56
|
+
end
|
57
|
+
def_sig :+, Schema
|
58
|
+
|
59
|
+
def []=(attr,types)
|
60
|
+
raise Duplicates,
|
61
|
+
"#{attr.inspect} results in duplicates " \
|
62
|
+
"in schema #{self.attributes}" unless self[attr].nil?
|
63
|
+
schema[attr] = types
|
64
|
+
end
|
65
|
+
def_sig :[]=, ConstAttribute, [RType]
|
66
|
+
|
67
|
+
def to_xml
|
68
|
+
_schema_ do
|
69
|
+
self.schema.collect do |attr,types|
|
70
|
+
col :name => attr.to_xml,
|
71
|
+
:type => types.collect { |ty| ty.to_xml }.join(",")
|
72
|
+
end.join
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def inspect
|
77
|
+
"<Schema [#{schema.map { |s| s.inspect }.join(", ")}]>"
|
78
|
+
end
|
79
|
+
|
80
|
+
def clone
|
81
|
+
Schema.new( self.schema.clone )
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Locomotive
|
2
|
+
|
3
|
+
module RelationalAlgebra
|
4
|
+
|
5
|
+
class RType
|
6
|
+
include Singleton
|
7
|
+
include Locomotive::XML
|
8
|
+
|
9
|
+
class << self
|
10
|
+
alias :type :instance
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize()
|
14
|
+
if self.class == RType
|
15
|
+
raise AbstractClassError,
|
16
|
+
"#{self.class} is an abstract class"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def clone
|
21
|
+
# since all types are singletons
|
22
|
+
# we can return the object itself
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_xml
|
27
|
+
self.class.to_s.split("::").last.downcase[1..-1]
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
"<#{self.class.to_s.split('::').last}>"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
class RDbl < RType; end
|
35
|
+
class RDec < RDbl; end
|
36
|
+
class RInt < RDec; end
|
37
|
+
class RNat < RInt; end
|
38
|
+
|
39
|
+
class RStr < RType; end
|
40
|
+
|
41
|
+
class RBool < RType; end
|
42
|
+
|
43
|
+
#
|
44
|
+
# An atomic value constists of a value an
|
45
|
+
# its associated type
|
46
|
+
#
|
47
|
+
class RAtomic
|
48
|
+
extend Locomotive::TypeChecking::Signature
|
49
|
+
include Locomotive::XML
|
50
|
+
|
51
|
+
def_node :_value_
|
52
|
+
|
53
|
+
attr_accessor :value,
|
54
|
+
:type
|
55
|
+
def_sig :type=, RType
|
56
|
+
|
57
|
+
def initialize(val, ty)
|
58
|
+
self.value,
|
59
|
+
self.type = val, ty
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_xml
|
63
|
+
_value_ :type => type.to_xml do
|
64
|
+
value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def clone
|
69
|
+
RAtomic.new(self.value,
|
70
|
+
self.type)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
[:r_dbl, :r_dec, :r_int, :r_nat, :r_str, :r_bool].each do |meth|
|
76
|
+
meth_ = meth.classify.to_sym
|
77
|
+
define_method(meth_) do |val|
|
78
|
+
RAtomic.new(val,
|
79
|
+
::Locomotive::RelationalAlgebra.
|
80
|
+
const_get(meth_).type)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'pp'
|
2
|
+
module Locomotive
|
3
|
+
|
4
|
+
module AstHelpers
|
5
|
+
|
6
|
+
# The purpose of this module is to enhance
|
7
|
+
# an instance with accessors on special labeled
|
8
|
+
# methods.
|
9
|
+
#
|
10
|
+
# Each instance of a class (with this module included)
|
11
|
+
# has methods
|
12
|
+
# *. o.ann_\w+
|
13
|
+
# *. o.ann_\w+=
|
14
|
+
# to set and read the annotations.
|
15
|
+
module Annotations
|
16
|
+
public
|
17
|
+
|
18
|
+
# overwrite the respond_to method
|
19
|
+
# to pretend there are ann_-methods
|
20
|
+
def respond_to? sym
|
21
|
+
@annotations ||= {}
|
22
|
+
if @annotations.keys.member?( sym.to_s[-1,1] != "=" ?
|
23
|
+
sym :
|
24
|
+
sym.to_s[0..-2].to_sym )
|
25
|
+
true
|
26
|
+
else
|
27
|
+
super.respond_to? sym
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# set method_missing to overwrite
|
32
|
+
# the behaviour of ann_-prefixed
|
33
|
+
# methods
|
34
|
+
def method_missing(key, *args)
|
35
|
+
key_str = key.to_s
|
36
|
+
|
37
|
+
# labeled ANN_PATTERN is not applicable in
|
38
|
+
# this case due to ?<data>
|
39
|
+
if /^ann_(?<data>\w+)=?/ =~ key_str
|
40
|
+
@annotations ||= {}
|
41
|
+
|
42
|
+
data_sym = "ann_#{data}".to_sym
|
43
|
+
if key_str[-1,1] == "=" then
|
44
|
+
@annotations[data_sym] = args[0]
|
45
|
+
else
|
46
|
+
@annotations[data_sym]
|
47
|
+
end
|
48
|
+
|
49
|
+
else
|
50
|
+
super.method_missing(key, *args)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/ast_traversal"
|
2
|
+
|
3
|
+
|
4
|
+
module Locomotive
|
5
|
+
|
6
|
+
module AstHelpers
|
7
|
+
|
8
|
+
# Implements the composite behaviour, thus a node with
|
9
|
+
# two children.
|
10
|
+
module AstNode
|
11
|
+
private
|
12
|
+
|
13
|
+
DEFAULT_TRAVERSE_STRATEGY = PreOrderTraverse
|
14
|
+
|
15
|
+
public
|
16
|
+
|
17
|
+
attr_accessor :kind,
|
18
|
+
:value,
|
19
|
+
:owner
|
20
|
+
|
21
|
+
attr_reader :left_child,
|
22
|
+
:right_child
|
23
|
+
|
24
|
+
# The owner denotes the parent
|
25
|
+
# of this node
|
26
|
+
|
27
|
+
# Initialize the node with values.</b>
|
28
|
+
# An <b>A</b>stract <b>S</b>yntax <b>T</b>ree-Node
|
29
|
+
# has a
|
30
|
+
# 1. kind
|
31
|
+
# 2. value
|
32
|
+
# 3. a left child
|
33
|
+
# 4. a right child
|
34
|
+
# 5. some node specific annotations
|
35
|
+
#
|
36
|
+
# The values 2. - 5. can be omitted because there can be
|
37
|
+
# some nodes with a kind only (e.g. separators).
|
38
|
+
# A node with neither left- nor right-child is a leaf-node.
|
39
|
+
def initialize(kind,
|
40
|
+
value = nil,
|
41
|
+
left = nil,
|
42
|
+
right = nil)
|
43
|
+
self.owner = nil
|
44
|
+
self.kind, self.value = kind, value
|
45
|
+
self.left_child = left if left != nil
|
46
|
+
self.right_child = right if right != nil
|
47
|
+
self.traverse_strategy = DEFAULT_TRAVERSE_STRATEGY
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sets a new left child
|
51
|
+
# and sets the owner which is the
|
52
|
+
# actual instance
|
53
|
+
def left_child=(child)
|
54
|
+
child.owner = self
|
55
|
+
@left_child = child
|
56
|
+
end
|
57
|
+
|
58
|
+
# Sets a new right child
|
59
|
+
# and sets the owner which is the
|
60
|
+
# actual instance
|
61
|
+
def right_child=(child)
|
62
|
+
child.owner = self
|
63
|
+
@right_child = child
|
64
|
+
end
|
65
|
+
|
66
|
+
def has_left_child?
|
67
|
+
self.left_child != nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def has_right_child?
|
71
|
+
self.right_child != nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# checks whether the node is a leaf
|
75
|
+
# or not
|
76
|
+
def is_leaf?
|
77
|
+
self.left_child == nil and
|
78
|
+
self.right_child == nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def traverse_strategy=(strategy)
|
82
|
+
@strategy = strategy
|
83
|
+
self.left_child.traverse_strategy = strategy if self.has_left_child?
|
84
|
+
self.right_child.traverse_strategy = strategy if self.has_right_child?
|
85
|
+
end
|
86
|
+
|
87
|
+
# Traverses the ast with a given
|
88
|
+
# strategy. If nothing given simple
|
89
|
+
# prefix-traversal is used
|
90
|
+
def traverse(strategy=nil, &block)
|
91
|
+
@strategy ||= strategy || DEFAULT_TRAVERSE_STRATEGY
|
92
|
+
@strategy.traverse(self, &block)
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Locomotive
|
2
|
+
|
3
|
+
module AstHelpers
|
4
|
+
|
5
|
+
class TraverseStrategy
|
6
|
+
def TraverseStrategy.traverse(ast, &block)
|
7
|
+
raise "Called abstract method traverse"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class PreOrderTraverse < TraverseStrategy
|
12
|
+
def PreOrderTraverse.traverse(ast, &block)
|
13
|
+
block.call(ast)
|
14
|
+
traverse(ast.left_child, &block) if ast.has_left_child?
|
15
|
+
traverse(ast.right_child, &block) if ast.has_right_child?
|
16
|
+
# return nothing
|
17
|
+
return
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class PostOrderTraverse < TraverseStrategy
|
22
|
+
def PostOrderTraverse.traverse(ast, &block)
|
23
|
+
traverse(ast.left_child, &block) if ast.has_left_child?
|
24
|
+
traverse(ast.right_child, &block) if ast.has_right_child?
|
25
|
+
block.call(ast)
|
26
|
+
# return nothing
|
27
|
+
return
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class InOrderTraverse < TraverseStrategy
|
32
|
+
def InOrderTraverse.traverse(ast, &block)
|
33
|
+
traverse(ast.left_child, &block) if ast.has_left_child?
|
34
|
+
block.call(ast)
|
35
|
+
traverse(ast.right_child, &block) if ast.has_right_child?
|
36
|
+
# return nothing
|
37
|
+
return
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|