Skip to content

Commit 2b244a2

Browse files
committed
add basic tests for pipeline eval
1 parent 377e82f commit 2b244a2

File tree

2 files changed

+334
-7
lines changed

2 files changed

+334
-7
lines changed

packages/firestore/src/core/expressions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ function asBigInt(protoNumber: { integerValue: number | string }): bigint {
281281
}
282282

283283
const LongMaxValue = BigInt('0x7fffffffffffffff');
284-
const LongMinValue = BigInt('-0x8000000000000000');
284+
const LongMinValue = -BigInt('0x8000000000000000');
285285

286286
abstract class BigIntOrDoubleArithmetics<
287287
T extends Add | Subtract | Multiply | Divide | Mod

packages/firestore/test/unit/core/pipeline.test.ts

Lines changed: 333 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,23 @@ import { Firestore } from '../../../src/api/database';
2121
import { CredentialsProvider } from '../../../src/api/credentials';
2222
import { User } from '../../../src/auth/user';
2323
import { DatabaseId } from '../../../src/core/database_info';
24-
import { Field, eq, Constant, doc as docRef } from '../../../src';
24+
import {
25+
Field,
26+
eq,
27+
Constant,
28+
doc as docRef,
29+
lt,
30+
lte,
31+
add,
32+
multiply,
33+
gt,
34+
gte
35+
} from '../../../src';
2536
import { canonifyPipeline, pipelineEq } from '../../../src/core/pipeline-util';
2637
import { runPipeline } from '../../../src/core/pipeline_run';
2738

2839
import { doc } from '../../util/helpers';
40+
import { and, or } from '../../../src/lite-api/expressions';
2941

3042
const fakeAuthProvider: CredentialsProvider<User> =
3143
{} as unknown as CredentialsProvider<User>;
@@ -210,16 +222,331 @@ describe.only('runPipeline()', () => {
210222
]);
211223
});
212224

213-
it('works with simple where', () => {
214-
const p = db.pipeline().collection('test').where(eq(`foo`, 42));
225+
it('works with collection groups', () => {
226+
const p = db.pipeline().collectionGroup('test');
215227

216228
expect(
217229
runPipeline(p, [
218230
doc('test/doc1', 1000, { foo: 'bar' }),
219-
doc('testNot/doc2', 1000, { foo: 'baz' }),
220-
doc('test/doc2', 1000, { foo: 42 }),
221-
doc('test/doc3', 1000, { foo: '42' })
231+
doc('testNot/doc2/test/doc2', 1000, { foo: 'baz' }),
232+
doc('test1/doc2', 1000, { foo: 'bazzzz' })
222233
])
234+
).to.deep.equal([
235+
doc('test/doc1', 1000, { foo: 'bar' }),
236+
doc('testNot/doc2/test/doc2', 1000, { foo: 'baz' })
237+
]);
238+
});
239+
240+
it('works with database', () => {
241+
const p = db.pipeline().database();
242+
243+
expect(
244+
runPipeline(p, [
245+
doc('test/doc1', 1000, { foo: 'bar' }),
246+
doc('testNot/doc2/test/doc2', 1000, { foo: 'baz' }),
247+
doc('test1/doc2', 1000, { foo: 'bazzzz' })
248+
])
249+
).to.deep.equal([
250+
doc('test/doc1', 1000, { foo: 'bar' }),
251+
doc('testNot/doc2/test/doc2', 1000, { foo: 'baz' }),
252+
doc('test1/doc2', 1000, { foo: 'bazzzz' })
253+
]);
254+
});
255+
256+
it('works with simple wheres', () => {
257+
const dataset = [
258+
doc('test/doc1', 1000, { foo: 'bar' }),
259+
doc('testNot/doc2', 1000, { foo: 'baz' }),
260+
doc('test/doc2', 1000, { foo: 42 }),
261+
doc('test/doc3', 1000, { foo: '42' })
262+
];
263+
264+
expect(
265+
runPipeline(
266+
db.pipeline().collection('test').where(eq(`foo`, 42)),
267+
dataset
268+
)
223269
).to.deep.equal([doc('test/doc2', 1000, { foo: 42 })]);
270+
271+
expect(
272+
runPipeline(
273+
db
274+
.pipeline()
275+
.collection('test')
276+
.where(or(eq(`foo`, 42), eq('foo', 'bar'))),
277+
dataset
278+
)
279+
).to.deep.equal([
280+
doc('test/doc1', 1000, { foo: 'bar' }),
281+
doc('test/doc2', 1000, { foo: 42 })
282+
]);
283+
284+
expect(
285+
runPipeline(
286+
db.pipeline().collection('test').where(lte(`foo`, '42')),
287+
dataset
288+
)
289+
).to.deep.equal([
290+
doc('test/doc2', 1000, { foo: 42 }),
291+
doc('test/doc3', 1000, { foo: '42' })
292+
]);
293+
});
294+
295+
// a representative dataset
296+
const bookDataset = [
297+
doc('test/book0', 1000, {
298+
title: "The Hitchhiker's Guide to the Galaxy",
299+
author: 'Douglas Adams',
300+
genre: 'Science Fiction',
301+
published: 1979,
302+
rating: 4.2,
303+
tags: ['comedy', 'space', 'adventure'],
304+
awards: {
305+
hugo: true,
306+
nebula: false,
307+
others: { unknown: { year: 1980 } }
308+
},
309+
nestedField: { 'level.1': { 'level.2': true } }
310+
}),
311+
doc('test/book1', 1000, {
312+
title: 'Pride and Prejudice',
313+
author: 'Jane Austen',
314+
genre: 'Romance',
315+
published: 1813,
316+
rating: 4.5,
317+
tags: ['classic', 'social commentary', 'love'],
318+
awards: { none: true }
319+
}),
320+
doc('test/book2', 1000, {
321+
title: 'One Hundred Years of Solitude',
322+
author: 'Gabriel García Márquez',
323+
genre: 'Magical Realism',
324+
published: 1967,
325+
rating: 4.3,
326+
tags: ['family', 'history', 'fantasy'],
327+
awards: { nobel: true, nebula: false }
328+
}),
329+
doc('test/book3', 1000, {
330+
title: 'The Lord of the Rings',
331+
author: 'J.R.R. Tolkien',
332+
genre: 'Fantasy',
333+
published: 1954,
334+
rating: 4.7,
335+
tags: ['adventure', 'magic', 'epic'],
336+
awards: { hugo: false, nebula: false }
337+
}),
338+
doc('test/book4', 1000, {
339+
title: "The Handmaid's Tale",
340+
author: 'Margaret Atwood',
341+
genre: 'Dystopian',
342+
published: 1985,
343+
rating: 4.1,
344+
tags: ['feminism', 'totalitarianism', 'resistance'],
345+
awards: { 'arthur c. clarke': true, 'booker prize': false }
346+
}),
347+
doc('test/book5', 1000, {
348+
title: 'Crime and Punishment',
349+
author: 'Fyodor Dostoevsky',
350+
genre: 'Psychological Thriller',
351+
published: 1866,
352+
rating: 4.3,
353+
tags: ['philosophy', 'crime', 'redemption'],
354+
awards: { none: true }
355+
}),
356+
doc('test/book6', 1000, {
357+
title: 'To Kill a Mockingbird',
358+
author: 'Harper Lee',
359+
genre: 'Southern Gothic',
360+
published: 1960,
361+
rating: 4.2,
362+
tags: ['racism', 'injustice', 'coming-of-age'],
363+
awards: { pulitzer: true }
364+
}),
365+
doc('test/book7', 1000, {
366+
title: '1984',
367+
author: 'George Orwell',
368+
genre: 'Dystopian',
369+
published: 1949,
370+
rating: 4.2,
371+
tags: ['surveillance', 'totalitarianism', 'propaganda'],
372+
awards: { prometheus: true }
373+
}),
374+
doc('test/book8', 1000, {
375+
title: 'The Great Gatsby',
376+
author: 'F. Scott Fitzgerald',
377+
genre: 'Modernist',
378+
published: 1925,
379+
rating: 4.0,
380+
tags: ['wealth', 'american dream', 'love'],
381+
awards: { none: true }
382+
}),
383+
doc('test/book9', 1000, {
384+
title: 'Dune',
385+
author: 'Frank Herbert',
386+
genre: 'Science Fiction',
387+
published: 1965,
388+
rating: 4.6,
389+
tags: ['politics', 'desert', 'ecology'],
390+
awards: { hugo: true, nebula: true }
391+
})
392+
];
393+
394+
it('works with array contains', () => {
395+
const p = db
396+
.pipeline()
397+
.collection('test')
398+
.where(Field.of('tags').arrayContains('adventure'));
399+
400+
expect(runPipeline(p, bookDataset)).to.deep.equal([
401+
bookDataset[0],
402+
bookDataset[3]
403+
]);
404+
});
405+
406+
it('works with array contains all', () => {
407+
const p = db
408+
.pipeline()
409+
.collection('test')
410+
.where(Field.of('tags').arrayContainsAll('adventure', 'magic'));
411+
412+
expect(runPipeline(p, bookDataset)).to.deep.equal([bookDataset[3]]);
413+
});
414+
415+
it('works with array contains any', () => {
416+
const p = db
417+
.pipeline()
418+
.collection('test')
419+
.where(Field.of('tags').arrayContainsAny('adventure', 'classic'));
420+
421+
expect(runPipeline(p, bookDataset)).to.deep.equal([
422+
bookDataset[0],
423+
bookDataset[1],
424+
bookDataset[3]
425+
]);
426+
});
427+
428+
it('works with string queries', () => {
429+
const p = db
430+
.pipeline()
431+
.collection('test')
432+
.where(Field.of('title').startsWith('The'));
433+
434+
expect(runPipeline(p, bookDataset)).to.deep.equal([
435+
bookDataset[0],
436+
bookDataset[3],
437+
bookDataset[4],
438+
bookDataset[8]
439+
]);
440+
441+
const p2 = db
442+
.pipeline()
443+
.collection('test')
444+
.where(Field.of('title').endsWith('Tale'));
445+
446+
expect(runPipeline(p2, bookDataset)).to.deep.equal([bookDataset[4]]);
447+
448+
const p3 = db
449+
.pipeline()
450+
.collection('test')
451+
.where(Field.of('title').strContains('Guide'));
452+
453+
expect(runPipeline(p3, bookDataset)).to.deep.equal([bookDataset[0]]);
454+
});
455+
456+
it('works with like queries', () => {
457+
const p = db
458+
.pipeline()
459+
.collection('test')
460+
.where(Field.of('title').like('%the%'));
461+
462+
expect(runPipeline(p, bookDataset)).to.deep.equal([
463+
bookDataset[0],
464+
bookDataset[3]
465+
]);
466+
});
467+
468+
it('works with limit', () => {
469+
const p = db.pipeline().collection('test').limit(3);
470+
471+
expect(runPipeline(p, bookDataset)).to.deep.equal([
472+
bookDataset[0],
473+
bookDataset[1],
474+
bookDataset[2]
475+
]);
476+
});
477+
478+
it('works with offset', () => {
479+
const p = db.pipeline().collection('test').offset(3).limit(3);
480+
481+
expect(runPipeline(p, bookDataset)).to.deep.equal([
482+
bookDataset[3],
483+
bookDataset[4],
484+
bookDataset[5]
485+
]);
486+
});
487+
488+
it('works with regex operations', () => {
489+
const p = db
490+
.pipeline()
491+
.collection('test')
492+
.where(Field.of('title').regexMatch('^The.*ings'));
493+
494+
expect(runPipeline(p, bookDataset)).to.deep.equal([bookDataset[3]]);
495+
496+
const p2 = db
497+
.pipeline()
498+
.collection('test')
499+
.where(Field.of('title').regexContains('Guide'));
500+
501+
expect(runPipeline(p2, bookDataset)).to.deep.equal([bookDataset[0]]);
502+
});
503+
504+
it('works with arithmetics', () => {
505+
const p = db
506+
.pipeline()
507+
.collection('test')
508+
.where(multiply(Field.of('published'), Field.of('rating')).gte(9000));
509+
510+
expect(runPipeline(p, bookDataset)).to.deep.equal([
511+
bookDataset[3],
512+
bookDataset[9]
513+
]);
514+
});
515+
516+
it('works with logical operators', () => {
517+
const p = db
518+
.pipeline()
519+
.collection('test')
520+
.where(
521+
and(lt(Field.of('published'), 1900), gte(Field.of('rating'), 4.5))
522+
);
523+
524+
expect(runPipeline(p, bookDataset)).to.deep.equal([bookDataset[1]]);
525+
});
526+
527+
it('works with sort', () => {
528+
const p = db
529+
.pipeline()
530+
.collection('test')
531+
.sort(Field.of('published').ascending())
532+
.limit(3);
533+
534+
expect(runPipeline(p, bookDataset)).to.deep.equal([
535+
bookDataset[1],
536+
bookDataset[5],
537+
bookDataset[8]
538+
]);
539+
540+
const p2 = db
541+
.pipeline()
542+
.collection('test')
543+
.sort(Field.of('published').descending())
544+
.limit(3);
545+
546+
expect(runPipeline(p2, bookDataset)).to.deep.equal([
547+
bookDataset[4],
548+
bookDataset[0],
549+
bookDataset[2]
550+
]);
224551
});
225552
});

0 commit comments

Comments
 (0)