mirror of
https://github.com/appy-one/acebase.git
synced 2026-05-25 22:01:21 -06:00
685 lines
24 KiB
JavaScript
685 lines
24 KiB
JavaScript
/// <reference types='@types/jasmine' />
|
|
const { DataReference, DataSnapshotsArray, DataReferencesArray, DataReferenceQuery, ObjectCollection } = require('acebase-core');
|
|
const { AceBase, ID } = require('..');
|
|
const { createTempDB } = require('./tempdb');
|
|
|
|
describe('Query', () => {
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
|
|
/** @type {DataReference} */
|
|
let moviesRef;
|
|
|
|
/** @type {Array<{ query: DataReferenceQuery, expect: object[] }>} */
|
|
let tests = [];
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
moviesRef = db.ref('movies');
|
|
|
|
const movies = require('./dataset/movies.json');
|
|
await moviesRef.set(ObjectCollection.from(movies));
|
|
|
|
tests.push({
|
|
query: moviesRef.query().filter('year', 'between', [1995, 2010]).filter('rating', '>=', 7).filter('genres', '!contains', ['sci-fi', 'fantasy']),
|
|
expect: movies.filter(movie => movie.year >= 1995 && movie.year <= 2010 && movie.rating >= 7 && movie.genres.every(g => !['sci-fi', 'fantasy'].includes(g))),
|
|
}, {
|
|
query: moviesRef.query().filter('genres', 'contains', ['action']),
|
|
expect: movies.filter(movie => movie.genres.includes('action')),
|
|
}, {
|
|
query: moviesRef.query().filter('year', 'in', [1994, 1995]),
|
|
expect: movies.filter(movie => [1994, 1995].includes(movie.year)),
|
|
});
|
|
});
|
|
|
|
it('snapshots', async () => {
|
|
for (let test of tests) {
|
|
const snaps = await test.query.get();
|
|
expect(snaps instanceof DataSnapshotsArray).toBeTrue();
|
|
expect(snaps.length).toBe(test.expect.length);
|
|
|
|
// Check if all expected movies are in the result
|
|
for (let movie of snaps.getValues()) {
|
|
const expectedMovie = test.expect.find(m => m.id === movie.id);
|
|
expect(typeof expectedMovie === 'object');
|
|
}
|
|
}
|
|
});
|
|
|
|
it('snapshots with include option', async () => {
|
|
for (let test of tests) {
|
|
const snaps = await test.query.get({ include: ['id','title'] });
|
|
expect(snaps instanceof DataSnapshotsArray).toBeTrue();
|
|
expect(snaps.length).toBe(test.expect.length);
|
|
|
|
// Check if all expected movies are in the result
|
|
for (let movie of snaps.getValues()) {
|
|
const expectedMovie = test.expect.find(m => m.id === movie.id);
|
|
expect(typeof expectedMovie === 'object');
|
|
|
|
// Also check if the value only has id & title properties
|
|
const properties = Object.keys(movie).sort();
|
|
expect(properties.length).toBe(2);
|
|
expect(properties[0]).toBe('id');
|
|
expect(properties[1]).toBe('title');
|
|
}
|
|
}
|
|
});
|
|
|
|
it('snapshots with exclude option', async () => {
|
|
for (let test of tests) {
|
|
const snaps = await test.query.get({ exclude: ['description'] });
|
|
expect(snaps instanceof DataSnapshotsArray).toBeTrue();
|
|
expect(snaps.length).toBe(test.expect.length);
|
|
|
|
// Check if all expected movies are in the result
|
|
for (let movie of snaps.getValues()) {
|
|
const expectedMovie = test.expect.find(m => m.id === movie.id);
|
|
expect(typeof expectedMovie === 'object');
|
|
|
|
// Also check if the value does not have a description property
|
|
expect('description' in movie).toBeFalse();
|
|
}
|
|
}
|
|
});
|
|
|
|
it('references', async () => {
|
|
for (let test of tests) {
|
|
const refs = await test.query.find();
|
|
expect(refs instanceof DataReferencesArray).toBeTrue();
|
|
expect(refs.length).toBe(test.expect.length);
|
|
}
|
|
});
|
|
|
|
it('count', async () => {
|
|
for (let test of tests) {
|
|
const count = await test.query.count();
|
|
expect(count).toBe(test.expect.length);
|
|
}
|
|
});
|
|
|
|
it('exists', async () => {
|
|
for (let test of tests) {
|
|
const exists = await test.query.exists();
|
|
expect(exists).toBe(test.expect.length > 0);
|
|
}
|
|
});
|
|
|
|
it('is live', async () => {
|
|
// Code based on realtime query example in README.md
|
|
const wait = async (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
const fiveStarBooks = {}; // local query result set
|
|
const query = db.query('books')
|
|
.filter('rating', '==', 5)
|
|
.on('add', match => {
|
|
// add book to results
|
|
fiveStarBooks[match.snapshot.key] = match.snapshot.val();
|
|
})
|
|
.on('change', match => {
|
|
// update book details
|
|
fiveStarBooks[match.snapshot.key] = match.snapshot.val();
|
|
})
|
|
.on('remove', match => {
|
|
// remove book from results
|
|
delete fiveStarBooks[match.ref.key];
|
|
});
|
|
const snaps = await query.get();
|
|
|
|
// Add current query results to our local result set
|
|
snaps.forEach(snap => {
|
|
fiveStarBooks[snap.key] = snap.val();
|
|
});
|
|
|
|
const countBooks = () => Object.keys(fiveStarBooks).length;
|
|
|
|
// Collection is empty, so there should be 0 results
|
|
expect(countBooks()).toBe(0);
|
|
|
|
// Let's add a non-matching book
|
|
await db.ref('books').push({ title: 'Some mediocre novel', rating: 3 });
|
|
|
|
// Wait few ms to make sure results are (not) being updated
|
|
await wait(10);
|
|
|
|
// Collection should still be 0
|
|
expect(countBooks()).toBe(0);
|
|
|
|
// Add a matching book
|
|
let matchRef1 = await db.ref('books').push({ title: 'A very good novel', rating: 5 });
|
|
|
|
// Wait few ms to make sure results are being updated
|
|
await wait(10);
|
|
|
|
// Collection should now contain 1 book
|
|
expect(countBooks()).toBe(1);
|
|
|
|
// Change the rating so it doesn't match anymore
|
|
await matchRef1.update({ rating: 4 });
|
|
await wait(10); // Wait few ms
|
|
expect(countBooks()).toBe(0);
|
|
|
|
// Change rating back to 5
|
|
await matchRef1.update({ rating: 5 });
|
|
await wait(10); // Wait few ms
|
|
expect(countBooks()).toBe(1);
|
|
|
|
// Stop query
|
|
await query.stop();
|
|
|
|
// Change the rating so it doesn't match anymore
|
|
await matchRef1.update({ rating: 4 });
|
|
await wait(10); // Wait few ms
|
|
expect(countBooks()).toBe(1); // Should not have received a callback because of previous .stop()
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
});
|
|
|
|
describe('Query with take/skip', () => {
|
|
// Based on https://github.com/appy-one/acebase/issues/75
|
|
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
|
|
const updates = {};
|
|
for (let i = 0; i < 2000; i++) {
|
|
updates[ID.generate()] = { letter: String.fromCharCode(97 + Math.floor(Math.random() * 26)) };
|
|
}
|
|
|
|
// create non-indexed collection
|
|
await db.ref('collection').update(updates);
|
|
|
|
// create indexed collection
|
|
await db.indexes.create('indexed_collection', 'letter'); // | Swap these to
|
|
await db.ref('indexed_collection').update(updates); // | improve performance
|
|
|
|
}, 60e3);
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
|
|
// Non-indexed:
|
|
|
|
it('load first 100 sort letter by a-z (non-indexed)', async () => {
|
|
const results = await db.query('collection').sort('letter', true).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load second 100 sort letter by a-z (non-indexed)', async () => {
|
|
const results = await db.query('collection').sort('letter', true).skip(100).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load third 100 sort letter by a-z (non-indexed)', async () => {
|
|
const results = await db.query('collection').sort('letter', true).skip(200).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load first 100 sort letter by z-a (non-indexed)', async () => {
|
|
const results = await db.query('collection').sort('letter', false).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load second 100 sort letter by z-a (non-indexed)', async () => {
|
|
const results = await db.query('collection').sort('letter', false).skip(100).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load third 100 sort letter by z-a (non-indexed)', async () => {
|
|
const results = await db.query('collection').sort('letter', false).skip(200).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
// Indexed:
|
|
|
|
it('load first 100 sort letter by a-z (indexed)', async () => {
|
|
const results = await db.query('indexed_collection').sort('letter', true).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load second 100 sort letter by a-z (indexed)', async () => {
|
|
const results = await db.query('indexed_collection').sort('letter', true).skip(100).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load third 100 sort letter by a-z (indexed)', async () => {
|
|
const results = await db.query('indexed_collection').sort('letter', true).skip(200).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load first 100 sort letter by z-a (indexed)', async () => {
|
|
const results = await db.query('indexed_collection').sort('letter', false).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load second 100 sort letter by z-a (indexed)', async () => {
|
|
const results = await db.query('indexed_collection').sort('letter', false).skip(100).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('load third 100 sort letter by z-a (indexed)', async () => {
|
|
const results = await db.query('indexed_collection').sort('letter', false).skip(200).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
}, 30e3);
|
|
|
|
it('without sort', async() => {
|
|
// skip/take without sort, created for #119
|
|
const results = await db.query('collection').skip(200).take(100).get();
|
|
expect(results.length).toBe(100);
|
|
});
|
|
|
|
});
|
|
|
|
describe('Query with take/skip multiple sorts', () => {
|
|
// Based on the test created for issue #120 (see below)
|
|
// This test performs an index take/skip with a sort on multiple fields (included in the index),
|
|
// which is a new feature added in v1.24.0
|
|
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
/** @type Array<{ id: string; title: string; year: number }> */
|
|
let movies;
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
|
|
movies = require('./dataset/movies.json');
|
|
const collection = ObjectCollection.from(movies);
|
|
|
|
// Create unindexed collection
|
|
await db.ref('movies').set(collection);
|
|
|
|
// Create indexed collection
|
|
await db.ref('indexed_movies').set(collection);
|
|
await db.indexes.create('indexed_movies', 'year', { include: ['title'] });
|
|
}, 60e3);
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
|
|
it('skip unindexed', async () => {
|
|
const skip = 10, take = 5;
|
|
const query = db.query('movies')
|
|
.sort('year', false)
|
|
.sort('title')
|
|
.take(take)
|
|
.skip(skip);
|
|
const results = await query.get(); //({ include: ['id', 'title', 'year'] })
|
|
const check = movies.sort((a, b) => b.year === a.year ? a.title < b.title ? -1 : 1 : b.year - a.year).slice(skip, skip + take);
|
|
expect(results.getValues()).toEqual(check);
|
|
});
|
|
|
|
it('skip indexed', async () => {
|
|
const skip = 10, take = 5;
|
|
const query = db.query('indexed_movies')
|
|
.sort('year', false)
|
|
.sort('title')
|
|
.take(take)
|
|
.skip(skip);
|
|
const results = await query.get(); //({ include: ['id', 'title', 'year'] })
|
|
const check = movies.sort((a, b) => b.year === a.year ? a.title < b.title ? -1 : 1 : b.year - a.year).slice(skip, skip + take);
|
|
expect(results.getValues()).toEqual(check);
|
|
}, 30e6);
|
|
|
|
});
|
|
|
|
describe('Query with take/skip #120', () => {
|
|
// Based on https://github.com/appy-one/acebase/issues/120
|
|
// This test occasionally failed because the indexed field 'year' was not unique:
|
|
// performing a take/skip on either indexed or non-indexed data did not always return
|
|
// the same results, simply because there was no second sort to guarantee a consistent
|
|
// sort order. This test now uses the 'votes' field, which is unique in the currently
|
|
// used (movies) dataset
|
|
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
/** @type Array<{ id: string; title: string; votes: number }> */
|
|
let movies;
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
|
|
movies = require('./dataset/movies.json');
|
|
const collection = ObjectCollection.from(movies);
|
|
|
|
// Create unindexed collection
|
|
await db.ref('movies').set(collection);
|
|
|
|
// Create indexed collection
|
|
await db.ref('indexed_movies').set(collection);
|
|
await db.indexes.create('indexed_movies', 'votes');
|
|
}, 60e3);
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
|
|
it('skip unindexed', async () => {
|
|
const skip = 10, take = 5;
|
|
const query = db.query('movies').sort('votes', false).take(take).skip(skip);
|
|
const results = await query.get(); //({ include: ['id', 'title', 'year'] })
|
|
const check = movies.sort((a, b) => b.votes - a.votes).slice(skip, skip + take);
|
|
expect(results.getValues()).toEqual(check);
|
|
});
|
|
|
|
it('skip indexed', async () => {
|
|
const skip = 10, take = 5;
|
|
const query = db.query('indexed_movies').sort('votes', false).take(take).skip(skip);
|
|
const results = await query.get(); //({ include: ['id', 'title', 'year'] })
|
|
const check = movies.sort((a, b) => b.votes - a.votes).slice(skip, skip + take);
|
|
expect(results.getValues()).toEqual(check);
|
|
});
|
|
|
|
});
|
|
|
|
describe('Query with take/sort/indexes #124', () => {
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
/** @type Array<{ id: string; title: string; year: number }> */
|
|
let movies;
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
|
|
movies = require('./dataset/movies.json');
|
|
const collection = ObjectCollection.from(movies);
|
|
|
|
// Create collection
|
|
await db.ref('movies').set(collection);
|
|
|
|
// Create indexes
|
|
await db.indexes.create('movies', 'year');
|
|
await db.indexes.create('movies', 'title');
|
|
});
|
|
|
|
it('test', async () => {
|
|
// Query movies: filter by title, order by year (desc), take 10
|
|
|
|
const snaps = await db.query('movies')
|
|
.filter('title', 'like', 'the*')
|
|
.sort('year', false)
|
|
.take(20)
|
|
.get();
|
|
|
|
const results = snaps.getValues();
|
|
const check = movies.filter(m => m.title.match(/^the/i)).sort((a, b) => b.year - a.year).slice(0, 20);
|
|
|
|
expect(results).toEqual(check);
|
|
}, 60 * 60 * 1000);
|
|
});
|
|
|
|
describe('Wildcard query', () => {
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
|
|
it('wildcards need an index', async () => {
|
|
// Created for discussion 92: https://github.com/appy-one/acebase/discussions/92
|
|
// Changed schema to be users/uid/messages/messageid
|
|
// To test: npx jasmine ./spec/query.spec.js --filter='wildcards'
|
|
|
|
// Insert data without index
|
|
await db.ref('users/user1/messages').push({ text: 'First message' });
|
|
await db.ref('users/user2/messages').push({ text: 'Second message' });
|
|
await db.ref('users/user1/messages').push({ text: 'Third message' });
|
|
|
|
try {
|
|
await db.query('users/$username/messages').count();
|
|
fail('Should not be allowed');
|
|
}
|
|
catch(err) {
|
|
// Expected, scattered data query requires an index
|
|
}
|
|
|
|
// Remove data
|
|
await db.root.update({ users: null });
|
|
|
|
// Create an index on {key} (key of each message) and try again
|
|
await db.indexes.create('users/$username/messages', '{key}');
|
|
await db.ref('users/user1/messages').push({ text: 'First message' });
|
|
await db.ref('users/user2/messages').push({ text: 'Second message' });
|
|
await db.ref('users/user1/messages').push({ text: 'Third message' });
|
|
|
|
try {
|
|
// Query with filter matching all
|
|
const snaps = await db.query('users/$username/messages').filter('{key}', '!=', '').get();
|
|
expect(snaps.length).toBe(3);
|
|
|
|
let msgcount = await db.query('users/$username/messages').filter('{key}', '!=', '').count();
|
|
expect(msgcount).toBe(3);
|
|
}
|
|
catch(err) {
|
|
fail('Should be allowed');
|
|
}
|
|
|
|
try {
|
|
// Query without filter, index should automatically be selected with filter matching all
|
|
const snaps = await db.query('users/$username/messages').get();
|
|
expect(snaps.length).toBe(3);
|
|
|
|
let msgcount = await db.query('users/$username/messages').count();
|
|
expect(msgcount).toBe(3);
|
|
}
|
|
catch(err) {
|
|
fail('Should be allowed');
|
|
}
|
|
}, 60e3); // increased timeout for debugging
|
|
|
|
});
|
|
|
|
describe('Wildcard query with delete', () => {
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
/** @type {Array<{ votes: number }>} */
|
|
let movies;
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
|
|
movies = require('./dataset/movies.json');
|
|
const collection = ObjectCollection.from(movies);
|
|
await db.ref('movies/collection1').set(collection);
|
|
await db.ref('movies/collection2').set(collection);
|
|
await db.ref('movies/collection3').set(collection);
|
|
|
|
await db.indexes.create('movies/*', 'votes');
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
|
|
it('works', async () => {
|
|
const votes = 1_500_000;
|
|
const query = db.query('movies/*').filter('votes', '>', votes);
|
|
|
|
// confirm count delivers the correct amount
|
|
let count = await query.count();
|
|
let check = movies.filter(m => m.votes > votes).length * 3; // 3 collections
|
|
expect(count).toBe(check);
|
|
|
|
// exists should return true
|
|
let exists = await query.exists();
|
|
expect(exists).toBeTrue();
|
|
|
|
// delete those
|
|
await query.remove();
|
|
|
|
// check if count is now 0
|
|
count = await query.count();
|
|
expect(count).toBe(0);
|
|
|
|
// exists should now return false
|
|
exists = await query.exists();
|
|
expect(exists).toBeFalse();
|
|
|
|
// All other movies should be still there
|
|
count = await db.query('movies/*').count();
|
|
check = movies.filter(m => m.votes <= votes).length * 3; // 3 collections
|
|
expect(count).toBe(check);
|
|
});
|
|
});
|
|
|
|
describe('Query with array/contains #135', () => {
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
});
|
|
|
|
it('test', async () => {
|
|
await db.ref('food').push({
|
|
name: 'apple',
|
|
tags: ['fruit', 'sweet'],
|
|
});
|
|
await db.ref('food').push({
|
|
name: 'orange',
|
|
tags: ['fruit', 'sweet', 'sour'],
|
|
});
|
|
await db.ref('food').push({
|
|
name: 'tomato',
|
|
tags: ['vegetable', 'sour'],
|
|
});
|
|
await db.ref('food').push({
|
|
name: 'milk',
|
|
tags: ['drink', 'sweet'],
|
|
});
|
|
await db.ref('food').push({
|
|
name: 'water',
|
|
tags: ['drink'],
|
|
});
|
|
await db.ref('food').push({
|
|
name: 'salt',
|
|
tags: [],
|
|
});
|
|
|
|
const test = async () => {
|
|
let snaps = await db.query('food').filter('tags', 'contains', ['fruit', 'sweet']).get();
|
|
let values = snaps.getValues().map(v => v.name).sort();
|
|
expect(values).toEqual(['apple', 'orange']);
|
|
|
|
snaps = await db.query('food').filter('tags', 'contains', ['sweet']).get();
|
|
values = snaps.getValues().map(v => v.name).sort();
|
|
expect(values).toEqual(['apple', 'milk', 'orange']);
|
|
|
|
snaps = await db.query('food').filter('tags', 'contains', []).get();
|
|
values = snaps.getValues().map(v => v.name).sort();
|
|
expect(values).toEqual(['apple', 'milk', 'orange', 'salt', 'tomato', 'water']);
|
|
|
|
// Now test !contains
|
|
snaps = await db.query('food').filter('tags', '!contains', ['fruit', 'sweet']).get();
|
|
values = snaps.getValues().map(v => v.name).sort();
|
|
expect(values).toEqual(['salt', 'tomato', 'water']);
|
|
|
|
snaps = await db.query('food').filter('tags', '!contains', ['sweet']).get();
|
|
values = snaps.getValues().map(v => v.name).sort();
|
|
expect(values).toEqual(['salt', 'tomato', 'water']);
|
|
|
|
snaps = await db.query('food').filter('tags', '!contains', []).get();
|
|
values = snaps.getValues().map(v => v.name).sort();
|
|
expect(values).toEqual(['apple', 'milk', 'orange', 'salt', 'tomato', 'water']);
|
|
};
|
|
|
|
// Run tests without index
|
|
await test();
|
|
|
|
// Now add an array index, run same tests
|
|
await db.indexes.create('food', 'tags', { type: 'array' });
|
|
|
|
// Run tests with index
|
|
await test();
|
|
|
|
}, 60 * 60 * 1000);
|
|
});
|
|
|
|
describe('Query on indexed BigInts #141', () => {
|
|
// Created for https://github.com/appy-one/acebase/issues/141
|
|
|
|
/** @type {AceBase} */
|
|
let db;
|
|
/** @type {{(): Promise<void>}} */
|
|
let removeDB;
|
|
|
|
/** @type {DataReference} */
|
|
let moviesRef;
|
|
|
|
beforeAll(async () => {
|
|
({ db, removeDB } = await createTempDB());
|
|
moviesRef = db.ref('movies');
|
|
|
|
const movies = require('./dataset/movies.json').map(movie => {
|
|
return {
|
|
title: movie.title,
|
|
rating: movie.rating,
|
|
year: movie.year,
|
|
votes: BigInt(movie.votes),
|
|
};
|
|
});
|
|
await moviesRef.set(ObjectCollection.from(movies));
|
|
await db.indexes.create('movies', 'votes');
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await removeDB();
|
|
});
|
|
|
|
it('filter on BigInt', async () => {
|
|
let query = moviesRef.query().filter('votes', '>', BigInt(1_500_000));
|
|
let snaps = await query.get();
|
|
expect(snaps.length).toEqual(5);
|
|
|
|
// Try again, now with cached results
|
|
snaps = await query.get();
|
|
expect(snaps.length).toEqual(5);
|
|
}, 60e3);
|
|
|
|
it('filter on number', async () => {
|
|
let query = moviesRef.query().filter('year', '>', BigInt(1995));
|
|
let snaps = await query.get();
|
|
expect(snaps.length).toEqual(8);
|
|
|
|
// Try again, now with cached results
|
|
snaps = await query.get();
|
|
expect(snaps.length).toEqual(8);
|
|
}, 60e3);
|
|
});
|