piglet 0.1.1 → 0.1.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/README.rdoc +24 -4
- data/lib/piglet/field/binary_conditional.rb +15 -0
- data/lib/piglet/field/call_expression.rb +21 -0
- data/lib/piglet/field/infix_expression.rb +19 -0
- data/lib/piglet/field/literal.rb +20 -0
- data/lib/piglet/field/operators.rb +80 -0
- data/lib/piglet/field/prefix_expression.rb +23 -0
- data/lib/piglet/field/reference.rb +41 -0
- data/lib/piglet/field/rename.rb +13 -0
- data/lib/piglet/field/suffix_expression.rb +19 -0
- data/lib/piglet/inout/describe.rb +7 -0
- data/lib/piglet/inout/dump.rb +7 -0
- data/lib/piglet/inout/explain.rb +15 -0
- data/lib/piglet/inout/illustrate.rb +7 -0
- data/lib/piglet/inout/load.rb +31 -0
- data/lib/piglet/inout/output.rb +15 -0
- data/lib/piglet/inout/storage_types.rb +18 -0
- data/lib/piglet/inout/store.rb +19 -0
- data/lib/piglet/interpreter.rb +39 -7
- data/lib/piglet/relation/cogroup.rb +33 -0
- data/lib/piglet/relation/cross.rb +24 -0
- data/lib/piglet/relation/distinct.rb +18 -0
- data/lib/piglet/relation/filter.rb +15 -0
- data/lib/piglet/relation/foreach.rb +21 -0
- data/lib/piglet/relation/group.rb +23 -0
- data/lib/piglet/relation/join.rb +22 -0
- data/lib/piglet/relation/limit.rb +15 -0
- data/lib/piglet/relation/order.rb +31 -0
- data/lib/piglet/relation/relation.rb +179 -0
- data/lib/piglet/relation/sample.rb +15 -0
- data/lib/piglet/relation/split.rb +45 -0
- data/lib/piglet/relation/stream.rb +7 -0
- data/lib/piglet/relation/union.rb +21 -0
- data/lib/piglet.rb +40 -38
- data/spec/piglet/{field_spec.rb → field/reference_spec.rb} +22 -6
- data/spec/piglet/interpreter_spec.rb +51 -5
- data/spec/piglet/{relation_spec.rb → relation/relation_spec.rb} +6 -6
- data/spec/piglet/{split_spec.rb → relation/split_spec.rb} +8 -8
- data/spec/spec_helper.rb +0 -2
- metadata +39 -40
- data/examples/spike1.rb +0 -43
- data/examples/spike2.rb +0 -40
- data/lib/piglet/assignment.rb +0 -13
- data/lib/piglet/cogroup.rb +0 -31
- data/lib/piglet/cross.rb +0 -22
- data/lib/piglet/describe.rb +0 -5
- data/lib/piglet/distinct.rb +0 -16
- data/lib/piglet/dump.rb +0 -5
- data/lib/piglet/explain.rb +0 -13
- data/lib/piglet/field.rb +0 -40
- data/lib/piglet/field_expression_functions.rb +0 -62
- data/lib/piglet/field_function_expression.rb +0 -19
- data/lib/piglet/field_infix_expression.rb +0 -17
- data/lib/piglet/field_prefix_expression.rb +0 -21
- data/lib/piglet/field_rename.rb +0 -11
- data/lib/piglet/field_suffix_expression.rb +0 -17
- data/lib/piglet/filter.rb +0 -13
- data/lib/piglet/foreach.rb +0 -19
- data/lib/piglet/group.rb +0 -21
- data/lib/piglet/illustrate.rb +0 -5
- data/lib/piglet/join.rb +0 -20
- data/lib/piglet/limit.rb +0 -13
- data/lib/piglet/load.rb +0 -31
- data/lib/piglet/load_and_store.rb +0 -16
- data/lib/piglet/order.rb +0 -29
- data/lib/piglet/relation.rb +0 -177
- data/lib/piglet/sample.rb +0 -13
- data/lib/piglet/split.rb +0 -41
- data/lib/piglet/store.rb +0 -17
- data/lib/piglet/storing.rb +0 -13
- data/lib/piglet/stream.rb +0 -5
- data/lib/piglet/union.rb +0 -19
@@ -0,0 +1,22 @@
|
|
1
|
+
module Piglet
|
2
|
+
module Relation
|
3
|
+
class Join # :nodoc:
|
4
|
+
include Relation
|
5
|
+
|
6
|
+
def initialize(relation, description)
|
7
|
+
@join_fields = Hash[*description.select { |k, v| k.is_a?(Relation) }.flatten]
|
8
|
+
@sources = @join_fields.keys
|
9
|
+
@using = description[:using]
|
10
|
+
@parallel = description[:parallel]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
joins = @sources.map { |s| "#{s.alias} BY #{@join_fields[s]}" }.join(', ')
|
15
|
+
str = "JOIN #{joins}"
|
16
|
+
str << " USING \"#{@using.to_s}\"" if @using
|
17
|
+
str << " PARALLEL #{@parallel}" if @parallel
|
18
|
+
str
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Piglet
|
2
|
+
module Relation
|
3
|
+
class Order # :nodoc:
|
4
|
+
include Relation
|
5
|
+
|
6
|
+
def initialize(relation, fields, options)
|
7
|
+
options ||= {}
|
8
|
+
@sources, @parallel = [relation], options[:parallel]
|
9
|
+
@fields = fields.is_a?(Enumerable) ? fields : [fields]
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"ORDER #{@sources.first.alias} BY #{field_strings}"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def field_strings
|
19
|
+
@fields.map { |f| field_string(f) }.join(', ')
|
20
|
+
end
|
21
|
+
|
22
|
+
def field_string(f)
|
23
|
+
if f.is_a?(Enumerable)
|
24
|
+
"#{f[0]} #{f[1].to_s.upcase}"
|
25
|
+
else
|
26
|
+
f.to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
module Piglet
|
2
|
+
module Relation
|
3
|
+
module Relation
|
4
|
+
attr_reader :sources
|
5
|
+
|
6
|
+
# The name this relation will get in Pig Latin. Then name is generated when
|
7
|
+
# the relation is outputed by the interpreter, and will be unique.
|
8
|
+
def alias
|
9
|
+
@alias ||= Relation.next_alias
|
10
|
+
end
|
11
|
+
|
12
|
+
# GROUP
|
13
|
+
#
|
14
|
+
# x.group(:a) # => GROUP x By a
|
15
|
+
# x.group(:a, :b, :c) # => GROUP x BY (a, b, c)
|
16
|
+
# x.group([:a, :b, :c], :parallel => 3) # => GROUP x BY (a, b, c) PARALLEL 3
|
17
|
+
def group(*args)
|
18
|
+
grouping, options = split_at_options(args)
|
19
|
+
Group.new(self, [grouping].flatten, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
# DISTINCT
|
23
|
+
#
|
24
|
+
# x.distinct # => DISTINCT x
|
25
|
+
# x.distinct(:parallel => 5) # => DISTINCT x PARALLEL 5
|
26
|
+
def distinct(options={})
|
27
|
+
Distinct.new(self, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
# COGROUP
|
31
|
+
#
|
32
|
+
# x.cogroup(x => :a, y => :b) # => COGROUP x BY a, y BY b
|
33
|
+
# x.cogroup(x => :a, y => :b, z => :c) # => COGROUP x BY a, y BY b, z BY c
|
34
|
+
# x.cogroup(x => [:a, :b], y => [:c, :d]) # => COGROUP x BY (a, b), y BY (c, d)
|
35
|
+
# x.cogroup(x => :a, y => [:b, :inner]) # => COGROUP x BY a, y BY b INNER
|
36
|
+
# x.cogroup(x => :a, y => :b, :parallel => 5) # => COGROUP x BY a, y BY b PARALLEL 5
|
37
|
+
def cogroup(description)
|
38
|
+
Cogroup.new(self, description)
|
39
|
+
end
|
40
|
+
|
41
|
+
# CROSS
|
42
|
+
#
|
43
|
+
# x.cross(y) # => CROSS x, y
|
44
|
+
# x.cross(y, z, w) # => CROSS x, y, z, w
|
45
|
+
# x.cross([y, z], :parallel => 5) # => CROSS x, y, z, w PARALLEL 5
|
46
|
+
def cross(*args)
|
47
|
+
relations, options = split_at_options(args)
|
48
|
+
Cross.new(([self] + relations).flatten, options)
|
49
|
+
end
|
50
|
+
|
51
|
+
# FILTER
|
52
|
+
#
|
53
|
+
# x.filter { |r| r.a == r.b } # => FILTER x BY a == b
|
54
|
+
# x.filter { |r| r.a > r.b && r.c != 3 } # => FILTER x BY a > b AND c != 3
|
55
|
+
def filter
|
56
|
+
Filter.new(self, yield(self))
|
57
|
+
end
|
58
|
+
|
59
|
+
# FOREACH ... GENERATE
|
60
|
+
#
|
61
|
+
# x.foreach { |r| r.a } # => FOREACH x GENERATE a
|
62
|
+
# x.foreach { |r| [r.a, r.b] } # => FOREACH x GENERATE a, b
|
63
|
+
# x.foreach { |r| r.a.max } # => FOREACH x GENERATE MAX(a)
|
64
|
+
# x.foreach { |r| r.a.avg.as(:b) } # => FOREACH x GENERATE AVG(a) AS b
|
65
|
+
#
|
66
|
+
#--
|
67
|
+
#
|
68
|
+
# TODO: FOREACH a { b GENERATE c }
|
69
|
+
def foreach
|
70
|
+
Foreach.new(self, yield(self))
|
71
|
+
end
|
72
|
+
|
73
|
+
# JOIN
|
74
|
+
#
|
75
|
+
# x.join(x => :a, y => :b) # => JOIN x BY a, y BY b
|
76
|
+
# x.join(x => :a, y => :b, z => :c) # => JOIN x BY a, y BY b, z BY c
|
77
|
+
# x.join(x => :a, y => :b, :using => :replicated) # => JOIN x BY a, y BY b USING "replicated"
|
78
|
+
# x.join(x => :a, y => :b, :parallel => 5) # => JOIN x BY a, y BY b PARALLEL 5
|
79
|
+
def join(description)
|
80
|
+
Join.new(self, description)
|
81
|
+
end
|
82
|
+
|
83
|
+
# LIMIT
|
84
|
+
#
|
85
|
+
# x.limit(10) # => LIMIT x 10
|
86
|
+
def limit(n)
|
87
|
+
Limit.new(self, n)
|
88
|
+
end
|
89
|
+
|
90
|
+
# ORDER
|
91
|
+
#
|
92
|
+
# x.order(:a) # => ORDER x BY a
|
93
|
+
# x.order(:a, :b) # => ORDER x BY a, b
|
94
|
+
# x.order([:a, :asc], [:b, :desc]) # => ORDER x BY a ASC, b DESC
|
95
|
+
# x.order(:a, :parallel => 5) # => ORDER x BY a PARALLEL 5
|
96
|
+
#
|
97
|
+
#--
|
98
|
+
#
|
99
|
+
# NOTE: the syntax x.order(:a => :asc, :b => :desc) would be nice, but in
|
100
|
+
# Ruby 1.8 the order of the keys cannot be guaranteed.
|
101
|
+
def order(*args)
|
102
|
+
fields, options = split_at_options(args)
|
103
|
+
fields = *fields
|
104
|
+
Order.new(self, fields, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
# SAMPLE
|
108
|
+
#
|
109
|
+
# x.sample(5) # => SAMPLE x 5;
|
110
|
+
def sample(n)
|
111
|
+
Sample.new(self, n)
|
112
|
+
end
|
113
|
+
|
114
|
+
# SPLIT
|
115
|
+
#
|
116
|
+
# y, z = x.split { |r| [r.a <= 3, r.b > 4]} # => SPLIT x INTO y IF a <= 3, z IF a > 4
|
117
|
+
def split
|
118
|
+
Split.new(self, yield(self)).shards
|
119
|
+
end
|
120
|
+
|
121
|
+
# STREAM
|
122
|
+
#
|
123
|
+
# x.stream(x, 'cut -f 3') # => STREAM x THROUGH `cut -f 3`
|
124
|
+
# x.stream([x, y], 'cut -f 3') # => STREAM x, y THROUGH `cut -f 3`
|
125
|
+
# x.stream(x, 'cut -f 3', :schema => [%w(a int)]) # => STREAM x THROUGH `cut -f 3` AS (a:int)
|
126
|
+
#
|
127
|
+
#--
|
128
|
+
#
|
129
|
+
# TODO: how to handle DEFINE'd commands?
|
130
|
+
def stream(relations, command, options={})
|
131
|
+
raise NotSupportedError
|
132
|
+
end
|
133
|
+
|
134
|
+
# UNION
|
135
|
+
#
|
136
|
+
# x.union(y) # => UNION x, y
|
137
|
+
# x.union(y, z) # => UNION x, y, z
|
138
|
+
def union(*relations)
|
139
|
+
Union.new(*([self] + relations))
|
140
|
+
end
|
141
|
+
|
142
|
+
def method_missing(name, *args)
|
143
|
+
if name.to_s =~ /^\w+$/ && args.empty?
|
144
|
+
Field::Reference.new(name, self)
|
145
|
+
else
|
146
|
+
super
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def [](n)
|
151
|
+
Field::Reference.new("\$#{n}", self)
|
152
|
+
end
|
153
|
+
|
154
|
+
def hash
|
155
|
+
self.alias.hash
|
156
|
+
end
|
157
|
+
|
158
|
+
def eql?(other)
|
159
|
+
other.is_a?(Relation) && other.alias == self.alias
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def split_at_options(parameters)
|
165
|
+
if parameters.last.is_a? Hash
|
166
|
+
[parameters[0..-2], parameters.last]
|
167
|
+
else
|
168
|
+
[parameters, nil]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.next_alias
|
173
|
+
@counter ||= 0
|
174
|
+
@counter += 1
|
175
|
+
"relation_#{@counter}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Piglet
|
2
|
+
module Relation
|
3
|
+
class Split # :nodoc:
|
4
|
+
include Relation
|
5
|
+
|
6
|
+
def initialize(relation, expressions)
|
7
|
+
@sources, @expressions = [relation], expressions
|
8
|
+
@shard_map = create_shards
|
9
|
+
end
|
10
|
+
|
11
|
+
def shards
|
12
|
+
@shard_map.values_at(*@expressions)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
split_strings = @expressions.map do |expression|
|
17
|
+
"#{@shard_map[expression].alias} IF #{expression}"
|
18
|
+
end
|
19
|
+
|
20
|
+
"SPLIT #{@sources.first.alias} INTO #{split_strings.join(', ')}"
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def create_shards
|
26
|
+
@expressions.inject({}) do |map, expr|
|
27
|
+
map[expr] = RelationShard.new(self)
|
28
|
+
map
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class RelationShard # :nodoc:
|
34
|
+
include Relation
|
35
|
+
|
36
|
+
def initialize(split)
|
37
|
+
@sources = [split]
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
self.alias
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Piglet
|
2
|
+
module Relation
|
3
|
+
class Union # :nodoc:
|
4
|
+
include Relation
|
5
|
+
|
6
|
+
def initialize(*relations)
|
7
|
+
@sources = relations
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"UNION #{source_aliases.join(', ')}"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def source_aliases
|
17
|
+
@sources.map { |s| s.alias }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/piglet.rb
CHANGED
@@ -1,45 +1,47 @@
|
|
1
1
|
# :main: README.rdoc
|
2
2
|
module Piglet # :nodoc:
|
3
|
-
VERSION = '0.1.
|
3
|
+
VERSION = '0.1.2'
|
4
4
|
|
5
|
-
|
6
|
-
assignment
|
7
|
-
cogroup
|
8
|
-
cross
|
9
|
-
describe
|
10
|
-
distinct
|
11
|
-
dump
|
12
|
-
explain
|
13
|
-
field
|
14
|
-
field_expression_functions
|
15
|
-
field_function_expression
|
16
|
-
field_infix_expression
|
17
|
-
field_prefix_expression
|
18
|
-
field_rename
|
19
|
-
field_suffix_expression
|
20
|
-
filter
|
21
|
-
foreach
|
22
|
-
group
|
23
|
-
illustrate
|
24
|
-
interpreter
|
25
|
-
join
|
26
|
-
limit
|
27
|
-
load
|
28
|
-
load_and_store
|
29
|
-
order
|
30
|
-
relation
|
31
|
-
sample
|
32
|
-
split
|
33
|
-
store
|
34
|
-
storing
|
35
|
-
stream
|
36
|
-
union
|
37
|
-
)
|
5
|
+
autoload :Interpreter, 'piglet/interpreter'
|
38
6
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
autoload
|
7
|
+
module Inout
|
8
|
+
autoload :Describe, 'piglet/inout/describe'
|
9
|
+
autoload :Dump, 'piglet/inout/dump'
|
10
|
+
autoload :Explain, 'piglet/inout/explain'
|
11
|
+
autoload :Illustrate, 'piglet/inout/illustrate'
|
12
|
+
autoload :Load, 'piglet/inout/load'
|
13
|
+
autoload :Output, 'piglet/inout/output'
|
14
|
+
autoload :StorageTypes, 'piglet/inout/storage_types'
|
15
|
+
autoload :Store, 'piglet/inout/store'
|
16
|
+
end
|
17
|
+
|
18
|
+
module Relation
|
19
|
+
autoload :Cogroup, 'piglet/relation/cogroup'
|
20
|
+
autoload :Cross, 'piglet/relation/cross'
|
21
|
+
autoload :Distinct, 'piglet/relation/distinct'
|
22
|
+
autoload :Filter, 'piglet/relation/filter'
|
23
|
+
autoload :Foreach, 'piglet/relation/foreach'
|
24
|
+
autoload :Group, 'piglet/relation/group'
|
25
|
+
autoload :Join, 'piglet/relation/join'
|
26
|
+
autoload :Limit, 'piglet/relation/limit'
|
27
|
+
autoload :Order, 'piglet/relation/order'
|
28
|
+
autoload :Relation, 'piglet/relation/relation'
|
29
|
+
autoload :Sample, 'piglet/relation/sample'
|
30
|
+
autoload :Split, 'piglet/relation/split'
|
31
|
+
autoload :Stream, 'piglet/relation/stream'
|
32
|
+
autoload :Union, 'piglet/relation/union'
|
33
|
+
end
|
34
|
+
|
35
|
+
module Field
|
36
|
+
autoload :BinaryConditional, 'piglet/field/binary_conditional'
|
37
|
+
autoload :CallExpression, 'piglet/field/call_expression'
|
38
|
+
autoload :InfixExpression, 'piglet/field/infix_expression'
|
39
|
+
autoload :Literal, 'piglet/field/literal'
|
40
|
+
autoload :Operators, 'piglet/field/operators'
|
41
|
+
autoload :PrefixExpression, 'piglet/field/prefix_expression'
|
42
|
+
autoload :Reference, 'piglet/field/reference'
|
43
|
+
autoload :Rename, 'piglet/field/rename'
|
44
|
+
autoload :SuffixExpression, 'piglet/field/suffix_expression'
|
43
45
|
end
|
44
46
|
|
45
47
|
class NotSupportedError < StandardError; end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
2
|
|
3
3
|
|
4
|
-
describe Piglet::Field do
|
4
|
+
describe Piglet::Field::Reference do
|
5
5
|
|
6
6
|
before do
|
7
|
-
@field = Piglet::Field.new('field')
|
7
|
+
@field = Piglet::Field::Reference.new('field')
|
8
8
|
end
|
9
9
|
|
10
10
|
describe '#to_s' do
|
@@ -13,7 +13,7 @@ describe Piglet::Field do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'returns a string with the field name (as a symbol)' do
|
16
|
-
@field = Piglet::Field.new(:field)
|
16
|
+
@field = Piglet::Field::Reference.new(:field)
|
17
17
|
@field.to_s.should eql("field")
|
18
18
|
end
|
19
19
|
end
|
@@ -52,8 +52,8 @@ describe Piglet::Field do
|
|
52
52
|
|
53
53
|
context 'infix and unary operators' do
|
54
54
|
before do
|
55
|
-
@field1 = Piglet::Field.new('field1')
|
56
|
-
@field2 = Piglet::Field.new('field2')
|
55
|
+
@field1 = Piglet::Field::Reference.new('field1')
|
56
|
+
@field2 = Piglet::Field::Reference.new('field2')
|
57
57
|
end
|
58
58
|
|
59
59
|
[:==, :>, :<, :>=, :<=, :%, :+, :-, :*, :/].each do |op|
|
@@ -125,6 +125,22 @@ describe Piglet::Field do
|
|
125
125
|
it 'supports casts on an expression' do
|
126
126
|
(@field1 + @field2).cast(:chararray).to_s.should eql("(chararray) (field1 + field2)")
|
127
127
|
end
|
128
|
+
|
129
|
+
it 'supports AND though #and on fields' do
|
130
|
+
@field1.and(@field2).to_s.should eql("field1 AND field2")
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'supports AND through #and on expressions' do
|
134
|
+
(@field1 + @field2).and(@field1 - @field2).to_s.should eql("(field1 + field2) AND (field1 - field2)")
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'supports OR though #or on fields' do
|
138
|
+
@field1.or(@field2).to_s.should eql("field1 OR field2")
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'supports OR through #or on expressions' do
|
142
|
+
(@field1 + @field2).or(@field1 - @field2).to_s.should eql("(field1 + field2) OR (field1 - field2)")
|
143
|
+
end
|
128
144
|
end
|
129
145
|
|
130
146
|
end
|
@@ -40,7 +40,7 @@ describe Piglet::Interpreter do
|
|
40
40
|
@interpreter.to_pig_latin.should include("LOAD 'some/path' USING XYZ;")
|
41
41
|
end
|
42
42
|
|
43
|
-
Piglet::
|
43
|
+
Piglet::Inout::StorageTypes::LOAD_STORE_FUNCTIONS.each do |symbolic_name, function|
|
44
44
|
it "knows that the load method :#{symbolic_name} means #{function}" do
|
45
45
|
@interpreter.interpret { store(load('some/path', :using => symbolic_name), 'out') }
|
46
46
|
@interpreter.to_pig_latin.should include("LOAD 'some/path' USING #{function};")
|
@@ -267,10 +267,10 @@ describe Piglet::Interpreter do
|
|
267
267
|
@interpreter.to_pig_latin.should match(/FILTER \w+ BY a == 3/)
|
268
268
|
end
|
269
269
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
270
|
+
it 'outputs a FILTER statement with a complex test' do
|
271
|
+
@interpreter.interpret { dump(load('in').filter { |r| (r.a > r.b).and(r.c.ne(3)) }) }
|
272
|
+
@interpreter.to_pig_latin.should match(/FILTER \w+ BY \(a > b\) AND \(c != 3\)/)
|
273
|
+
end
|
274
274
|
end
|
275
275
|
|
276
276
|
describe 'SPLIT' do
|
@@ -410,4 +410,50 @@ describe Piglet::Interpreter do
|
|
410
410
|
end
|
411
411
|
end
|
412
412
|
|
413
|
+
context 'misc. operators' do
|
414
|
+
it 'outputs a binary conditional when using #test' do
|
415
|
+
@interpreter.interpret do
|
416
|
+
dump(load('in').foreach { |r| [test(r.a == r.b, r.a, r.b)]})
|
417
|
+
end
|
418
|
+
@interpreter.to_pig_latin.should include('(a == b ? a : b)')
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
context 'literals' do
|
423
|
+
it 'outputs a literal string when passing a string to #literal' do
|
424
|
+
@interpreter.interpret do
|
425
|
+
dump(load('in').foreach { |r| [literal('hello').as(:world)]})
|
426
|
+
end
|
427
|
+
@interpreter.to_pig_latin.should include("'hello' AS world")
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'outputs a literal integer when passing an integer to #literal' do
|
431
|
+
@interpreter.interpret do
|
432
|
+
dump(load('in').foreach { |r| [literal(3).as(:n)]})
|
433
|
+
end
|
434
|
+
@interpreter.to_pig_latin.should include("3 AS n")
|
435
|
+
end
|
436
|
+
|
437
|
+
it 'outputs a literal float when passing a float to #literal' do
|
438
|
+
@interpreter.interpret do
|
439
|
+
dump(load('in').foreach { |r| [literal(3.14).as(:pi)]})
|
440
|
+
end
|
441
|
+
@interpreter.to_pig_latin.should include("3.14 AS pi")
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'outputs a literal string when passing an arbitrary object to #literal' do
|
445
|
+
@interpreter.interpret do
|
446
|
+
dump(load('in').foreach { |r| [literal(self).as(:interpreter)]})
|
447
|
+
end
|
448
|
+
@interpreter.to_pig_latin.should match(/'[^']+' AS interpreter/)
|
449
|
+
end
|
450
|
+
|
451
|
+
it 'escapes single quotes in literal strings' do
|
452
|
+
@interpreter.interpret do
|
453
|
+
dump(load('in').foreach { |r| [literal("hello 'world'").as(:str)]})
|
454
|
+
end
|
455
|
+
@interpreter.to_pig_latin.should include("'hello \\'world\\'' AS str")
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
413
459
|
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
2
|
|
3
3
|
|
4
|
-
describe Piglet::Relation do
|
4
|
+
describe Piglet::Relation::Relation do
|
5
5
|
|
6
6
|
before do
|
7
7
|
@relation = Object.new
|
8
|
-
@relation.extend Piglet::Relation
|
8
|
+
@relation.extend Piglet::Relation::Relation
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'has a alias' do
|
@@ -16,7 +16,7 @@ describe Piglet::Relation do
|
|
16
16
|
aliases = { }
|
17
17
|
1000.times do
|
18
18
|
@relation = Object.new
|
19
|
-
@relation.extend Piglet::Relation
|
19
|
+
@relation.extend Piglet::Relation::Relation
|
20
20
|
aliases.should_not have_key(@relation.alias)
|
21
21
|
aliases[@relation.alias] = @relation
|
22
22
|
end
|
@@ -37,7 +37,7 @@ describe Piglet::Relation do
|
|
37
37
|
describe '#cross' do
|
38
38
|
it 'returns a new relation with the target relation as one of the sources' do
|
39
39
|
other = Object.new
|
40
|
-
other.extend Piglet::Relation
|
40
|
+
other.extend Piglet::Relation::Relation
|
41
41
|
@relation.cross(other).sources.should include(@relation)
|
42
42
|
end
|
43
43
|
end
|
@@ -45,7 +45,7 @@ describe Piglet::Relation do
|
|
45
45
|
describe '#union' do
|
46
46
|
it 'returns a new relation with the target relation as one of the sources' do
|
47
47
|
other = Object.new
|
48
|
-
other.extend Piglet::Relation
|
48
|
+
other.extend Piglet::Relation::Relation
|
49
49
|
@relation.union(other).sources.should include(@relation)
|
50
50
|
end
|
51
51
|
end
|
@@ -1,27 +1,27 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
2
|
|
3
3
|
|
4
|
-
describe Piglet::Split do
|
4
|
+
describe Piglet::Relation::Split do
|
5
5
|
|
6
6
|
before do
|
7
7
|
@relation = mock('source')
|
8
8
|
@expr1 = mock('expr1')
|
9
9
|
@expr2 = mock('expr2')
|
10
10
|
@relation.stub!(:alias).and_return('rel')
|
11
|
-
@expr1.stub!(:to_s).and_return('
|
12
|
-
@expr2.stub!(:to_s).and_return('
|
13
|
-
@split = Piglet::Split.new(@relation, [@expr1, @expr2])
|
11
|
+
@expr1.stub!(:to_s).and_return('expr1')
|
12
|
+
@expr2.stub!(:to_s).and_return('expr2')
|
13
|
+
@split = Piglet::Relation::Split.new(@relation, [@expr1, @expr2])
|
14
14
|
end
|
15
15
|
|
16
16
|
describe '#to_s' do
|
17
17
|
it 'outputs all x IF y expressions' do
|
18
|
-
@split.to_s.should match(/SPLIT rel INTO \w+ IF [
|
18
|
+
@split.to_s.should match(/SPLIT rel INTO \w+ IF expr[12], \w+ IF expr[12]/)
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'contains the names of all the shard relations' do
|
22
22
|
@shards = @split.shards
|
23
|
-
@split.to_s.should include("#{@shards[0].alias} IF
|
24
|
-
@split.to_s.should include("#{@shards[1].alias} IF
|
23
|
+
@split.to_s.should include("#{@shards[0].alias} IF expr1")
|
24
|
+
@split.to_s.should include("#{@shards[1].alias} IF expr2")
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|