Skip to content

Commit 598efa6

Browse files
authored
Merge pull request #639 from witheve/join
implement aggregate join by overriding the whole aggregate() method.
2 parents d9713fe + 2078e16 commit 598efa6

File tree

5 files changed

+141
-0
lines changed

5 files changed

+141
-0
lines changed

examples/join.eve

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
```
2+
commit
3+
[#foo token:"a" level:2]
4+
[#foo token:"zkp" level:3]
5+
[#foo token:"parg" level:0]
6+
[#foo token:"naxxo" level:1]
7+
```
8+
9+
```
10+
search
11+
[#foo token level]
12+
index = sort[value:token given:token]
13+
14+
commit @browser
15+
[#div text:join[token index given:token with:"/"]]
16+
[#div text:join[token index:0 given:token with:"/"]]
17+
[#div text:join[token index:level given:token with:"/"]]
18+
```

src/runtime/providers/aggregate.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,82 @@ export class Max extends Aggregate {
176176
}
177177
}
178178

179+
export class Join extends Aggregate {
180+
static AttributeMapping = {
181+
"value": 0,
182+
"given": 1,
183+
"per": 2,
184+
"index": 3,
185+
"with": 4,
186+
"token":0
187+
}
188+
189+
token : any;
190+
index : any;
191+
sepwith : any;
192+
193+
constructor(id: string, args: any[], returns: any[]) {
194+
super(id, args, returns);
195+
this.token = args[0]
196+
this.index = args[3]
197+
this.sepwith = args[4]
198+
}
199+
200+
aggregate(rows: any[]) {
201+
let groupKeys = [];
202+
let groups = {};
203+
for(let row of rows) {
204+
resolve(this.projectionVars, row, this.resolvedProjection)
205+
resolve(this.groupVars, row, this.resolvedGroup)
206+
let group = this.resolvedAggregate.group;
207+
let projection = this.resolvedAggregate.projection;
208+
let token = toValue(this.token, row);
209+
let index = toValue(this.index, row);
210+
let sepwith = toValue(this.sepwith, row);
211+
212+
if (sepwith === undefined) sepwith = "";
213+
214+
let groupKey = "[]";
215+
if(group.length !== 0) {
216+
groupKey = JSON.stringify(group);
217+
}
218+
let groupValues = groups[groupKey];
219+
if(groupValues === undefined) {
220+
groupKeys.push(groupKey);
221+
groupValues = groups[groupKey] = {result:[]};
222+
}
223+
let projectionKey = JSON.stringify(projection);
224+
if(groupValues[projectionKey] === undefined) {
225+
groupValues[projectionKey] = true;
226+
groupValues.result.push({token: token, index:index, sepwith:sepwith})
227+
}
228+
}
229+
230+
for (let g in groups) {
231+
let s = groups[g].result.sort((a, b) =>
232+
{if (a.index > b.index) return 1;
233+
if (a.index === b.index) return 0;
234+
return -1;})
235+
let len = s.length
236+
let result = ""
237+
for (var i=0; i<len; ++i) {
238+
// this means that the sep assocated with a value
239+
// is the one which occurs before the value
240+
if (i != 0) result += s[i].sepwith
241+
result += s[i].token
242+
}
243+
groups[g].result = result;
244+
}
245+
this.aggregateResults = groups;
246+
return groups;
247+
}
248+
// unused but to keep mr. class happy
249+
adjustAggregate(group, value, projection) {}
250+
}
251+
179252
providers.provide("sum", Sum);
180253
providers.provide("count", Count);
181254
providers.provide("average", Average);
255+
providers.provide("join", Join);
182256
providers.provide("min", Min);
183257
providers.provide("max", Max);

test/all.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import "./join";
22
import "./eavs";
33
import "./math";
4+
import "./strings";

test/shared_functions.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,27 @@ export function evaluate(assert, expected, code, session = new Database()) {
187187
return next;
188188
}
189189

190+
export function evaluates(assert, code, session = new Database()) {
191+
let parsed = parser.parseDoc(dedent(code), "0");
192+
let {blocks, errors} = builder.buildDoc(parsed.results);
193+
session.blocks = session.blocks.concat(blocks);
194+
let evaluation = new Evaluation();
195+
evaluation.registerDatabase("session", session);
196+
let changes = evaluation.fixpoint();
197+
198+
var success = false
199+
var inserts = changes.result().insert
200+
for(let triple of inserts) {
201+
if ((triple[1] === "tag") && (triple[2] === "success"))
202+
success = true;
203+
}
204+
if (success) {
205+
assert.true(true, "test complete");
206+
} else {
207+
assert.true(false, "test failed");
208+
}
209+
}
210+
190211
export interface valueTest {
191212
expression: string;
192213
expectedValue: number;

test/strings.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as test from "tape";
2+
import {evaluates} from "./shared_functions";
3+
4+
test("test string join ordering", (assert) => {
5+
evaluates(assert, `
6+
~~~
7+
commit
8+
[#foo token:"a" level:2]
9+
[#foo token:"zkp" level:3]
10+
[#foo token:"parg" level:0]
11+
[#foo token:"naxxo" level:1]
12+
~~~
13+
14+
~~~
15+
search
16+
[#foo token level]
17+
index = sort[value:token given:token]
18+
a = join[token index given:token with:"/"]
19+
a = "a/naxxo/parg/zkp"
20+
b = join[token index:level given:token with:"/"]
21+
b = "parg/naxxo/a/zkp"
22+
commit
23+
[#success]
24+
~~~
25+
`);
26+
assert.end();
27+
});

0 commit comments

Comments
 (0)