UNPKG

aerospike

Version:
256 lines (197 loc) 11.2 kB
// ***************************************************************************** // Copyright 2013-2024 Aerospike, Inc. // // Licensed under the Apache License, Version 2.0 (the "License") // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ***************************************************************************** 'use strict' /* eslint-env mocha */ /* global expect */ /* eslint-disable no-unused-expressions */ import type { Client, Query, Job as J, exp as expModule, cdt, AerospikeError as ASError, GeoJSON as GJ, GeoJSONType, RecordStream, Key as K, filter as filterModule, operations, indexDataType, indexType, QueryOptions, AerospikeRecord, AerospikeBins} from '../lib/aerospike.js'; import { expect } from 'chai'; import * as helper from './test_helper.ts'; import * as Aerospike from '../lib/aerospike.js'; const query: typeof Query = Aerospike.Query const Job: typeof J = Aerospike.Job const exp: typeof expModule = Aerospike.exp const Context: typeof cdt.Context = Aerospike.cdt.Context const AerospikeError: typeof ASError = Aerospike.AerospikeError const GeoJSON: typeof GJ= Aerospike.GeoJSON const Key: typeof K = Aerospike.Key const filter: typeof filterModule = Aerospike.filter const op: typeof operations = Aerospike.operations const NUMERIC: indexDataType = Aerospike.indexDataType.NUMERIC const STRING: indexDataType = Aerospike.indexDataType.STRING const GEO2DSPHERE: indexDataType = Aerospike.indexDataType.GEO2DSPHERE const BLOB: indexDataType = Aerospike.indexDataType.BLOB const LIST: indexType = Aerospike.indexType.LIST const MAPVALUES: indexType = Aerospike.indexType.MAPVALUES const MAPKEYS: indexType = Aerospike.indexType.MAPKEYS const keygen: any = helper.keygen const metagen: any = helper.metagen const putgen: any = helper.putgen let samples: any; describe('Queries', function () { const client: Client = helper.client if (!helper.cluster.isVersionInRange('>= 7.0.0')) { helper.skip(this, "Blob indexes require server version 7.0.0 or greater") } const testSet = 'test/query-' + Math.floor(Math.random() * 100000) samples = [ { name: 'blob match', blob: Buffer.from('guava') }, { name: 'blob non-match', blob: Buffer.from('pumpkin') }, { name: 'blob list match', lblob: [Buffer.from('guava'), Buffer.from('papaya')] }, { name: 'blob list non-match', lblob: [Buffer.from('pumpkin'), Buffer.from('turnip')] }, { name: 'blob map match', mblob: { a: Buffer.from('guava'), b: Buffer.from('papaya') } }, { name: 'blob map non-match', mblob: { a: Buffer.from('pumpkin'), b: Buffer.from('turnip') } }, { name: 'blob mapkeys match', mkblob: new Map([[Buffer.from('guava'), 1], [Buffer.from('papaya'), 2]]) }, { name: 'blob mapkeys non-match', mkblob: new Map([[Buffer.from('pumpkin'), 3], [Buffer.from('turnip'), 4]]) }, { name: 'nested blob match', blob: { nested: Buffer.from('guava') } }, { name: 'nested blob non-match', blob: { nested: Buffer.from('pumpkin') } }, { name: 'nested blob list match', lblob: { nested: [Buffer.from('guava'), Buffer.from('papaya')] } }, { name: 'nested blob list non-match', lblob: { nested: [Buffer.from('pumpkin'), Buffer.from('turnip')] } }, { name: 'nested blob map match', mblob: { nested: { a: Buffer.from('guava'), b: Buffer.from('papaya') } } }, { name: 'nested blob map non-match', mblob: { nested: { a: Buffer.from('pumpkin'), b: Buffer.from('turnip') } } }, { name: 'nested blob mapkeys match', mkblob: { nested: new Map([[Buffer.from('guava'), 1], [Buffer.from('papaya'), 2]]) } }, { name: 'nested blob mapkeys non-match', mkblob: { nested: new Map([[Buffer.from('pumpkin'), 3], [Buffer.from('turnip'), 4]]) } }, ] const indexes: any = [ ['qidxBlob', 'blob', BLOB], ['qidxBlobList', 'lblob', BLOB, LIST], ['qidxBlobMap', 'mblob', BLOB, MAPVALUES], ['qidxBlobMapKeys', 'mkblob', BLOB, MAPKEYS], ['qidxBlobListNested', 'lblob', BLOB, LIST, new Context().addMapKey('nested')], ['qidxBlobMapNested', 'mblob', BLOB, MAPVALUES, new Context().addMapKey('nested')], ['qidxBlobMapKeysNested', 'mkblob', BLOB, MAPKEYS, new Context().addMapKey('nested')], //['qidxBlobExp', exp.binBlob('blob'), BLOB], ] let keys: any = [] function verifyQueryResults (queryOptions: QueryOptions, matchName: string, done: any) { const query: Query = client.query(helper.namespace, testSet, queryOptions) let matches = 0 const stream: RecordStream = query.foreach() stream.on('error', (error: ASError) => { throw error }) stream.on('data', (record: AerospikeRecord) => { expect(record.bins).to.have.property('name', matchName) matches++ }) stream.on('end', function () { expect(matches).to.equal(1) done() }) } before(async () => { const generators: any = { keygen: keygen.string(helper.namespace, testSet, { prefix: 'test/query/', random: false }), recgen: () => samples.pop(), metagen: metagen.constant({ ttl: 300 }) } const numberOfSamples: any = samples.length let records: AerospikeRecord[] = await putgen.put(numberOfSamples, generators) keys = records.map((rec: AerospikeRecord) => rec.key) let promises: any = [] promises.push( helper.udf.register('udf.lua') ) for (let i in indexes){ let idx: any = indexes[i] promises.push(helper.index.create(idx[0], testSet, idx[1], idx[2], idx[3], idx[4])) } let result = await Promise.all(promises) }) after(async () => { let promises: any = [] promises.push( helper.udf.remove('udf.lua') ) for (let i in indexes){ let idx: any = indexes[i] promises.push( helper.index.remove(idx[0]) ) } let result = await Promise.all(promises) //await new Promise(r => setTimeout(r, 3000)); }) context('filter predicates', function () { describe('filter.equal()', function () { context('Uses blob Secondary indexes', function () { helper.skipUnlessVersion('>= 7.0.0', this) it('should match equal blob values', function (done) { const args: QueryOptions = { filters: [filter.equal('blob', Buffer.from('guava'))] } verifyQueryResults(args, 'blob match', done) }) context('Query using index name', function () { it('should match equal blob values using an index name', function (done) { const args: QueryOptions = { filters: [filter.equal(null, Buffer.from('guava'))] } args.filters![0].indexName = 'qidxBlob' verifyQueryResults(args, 'blob match', done) }) }) }) context('Uses blob Secondary indexes', function () { helper.skipUnlessVersion('>= 7.0.0', this) it('should match lists containing a blob', function (done) { const args: QueryOptions = { filters: [filter.contains('lblob', Buffer.from('guava'), LIST)] } verifyQueryResults(args, 'blob list match', done) }) it('should match lists containing a blob in a nested context', function (done) { const args: QueryOptions = { filters: [filter.contains('lblob', Buffer.from('guava'), LIST, new Context().addMapKey('nested'))] } verifyQueryResults(args, 'nested blob list match', done) }) it('should match maps containing a blob value', function (done) { const args: QueryOptions = { filters: [filter.contains('mblob', Buffer.from('guava'), MAPVALUES)] } verifyQueryResults(args, 'blob map match', done) }) it('should match maps containing a blob value in a nested context', function (done) { const args: QueryOptions = { filters: [filter.contains('mblob', Buffer.from('guava'), MAPVALUES, new Context().addMapKey('nested'))] } verifyQueryResults(args, 'nested blob map match', done) }) it('should match maps containing a blob key', function (done) { const args: QueryOptions = { filters: [filter.contains('mkblob', Buffer.from('guava'), MAPKEYS)] } verifyQueryResults(args, 'blob mapkeys match', done) }) it('should match maps containing a blob key in a nested context', function (done) { const args: QueryOptions = { filters: [filter.contains('mkblob', Buffer.from('guava'), MAPKEYS, new Context().addMapKey('nested'))] } verifyQueryResults(args, 'nested blob mapkeys match', done) }) context('Query using index name', function () { it('should match lists containing a blob using an index name', function (done) { const args: QueryOptions = { filters: [filter.contains(null, Buffer.from('guava'), LIST)] } args.filters![0].indexName = 'qidxBlobList' verifyQueryResults(args, 'blob list match', done) }) it('should match lists containing a blob in a nested context using an index name', function (done) { const args: QueryOptions = { filters: [filter.contains(null, Buffer.from('guava'), LIST, new Context().addMapKey('nested'))] } args.filters![0].indexName = 'qidxBlobListNested' verifyQueryResults(args, 'nested blob list match', done) }) it('should match maps containing a blob value using an index name', function (done) { const args: QueryOptions = { filters: [filter.contains(null, Buffer.from('guava'), MAPVALUES)] } args.filters![0].indexName = 'qidxBlobMap' verifyQueryResults(args, 'blob map match', done) }) it('should match maps containing a blob value in a nested context using an index name', function (done) { const args: QueryOptions = { filters: [filter.contains(null, Buffer.from('guava'), MAPVALUES, new Context().addMapKey('nested'))] } args.filters![0].indexName = 'qidxBlobMapNested' verifyQueryResults(args, 'nested blob map match', done) }) it('should match maps containing a blob key using an index name', function (done) { const args: QueryOptions = { filters: [filter.contains(null, Buffer.from('guava'), MAPKEYS)] } args.filters![0].indexName = 'qidxBlobMapKeys' verifyQueryResults(args, 'blob mapkeys match', done) }) it('should match maps containing a blob key in a nested context using an index name', function (done) { const args: QueryOptions = { filters: [filter.contains(null, Buffer.from('guava'), MAPKEYS, new Context().addMapKey('nested'))] } args.filters![0].indexName = 'qidxBlobMapKeysNested' verifyQueryResults(args, 'nested blob mapkeys match', done) }) }) }) }) }) })