UNPKG

aerospike

Version:
890 lines (593 loc) 34.6 kB
// ***************************************************************************** // Copyright 2022-2023 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 */ import {GeoJSON, hll} from '../lib/aerospike.js' import type { maps as Maps, AerospikeBins, RecordMetadata, Key, AerospikeRecord, AerospikeExp, operations, exp as expModule, cdt} from '../lib/aerospike.js'; import * as Aerospike from '../lib/aerospike.js'; const Context: typeof cdt.Context = Aerospike.cdt.Context import { expect, assert } from 'chai'; import * as helper from './test_helper.ts'; const exp: typeof expModule = Aerospike.exp const op: typeof operations = Aerospike.operations const pathSelectFlags: any = exp.pathSelectFlags const pathModifyFlags: any = exp.pathModifyFlags const loopVarPart: any = exp.loopVarPart const type: any = exp.type const keygen = helper.keygen const tempBin = 'ExpVar' describe('Aerospike.exp.selectByPath', async function () { const client = helper.client helper.skipUnlessVersion('>= 5.0.0', this) const key: Key = new Aerospike.Key(helper.namespace, helper.set, 1) const addAllChildren: cdt.Context = new Context().addAllChildren() const doubleAddAllChildren: cdt.Context = new Context().addAllChildren().addAllChildren() async function verifySelectByPath(bin: string, expression: AerospikeExp, expected: any, ) { const ops = [ exp.operations.read(bin, expression, exp.expReadFlags.DEFAULT) ] const result: any = await client.operate(key, ops) expect(expected).to.eql(result.bins[bin]) } async function verifyModifyByPath(bin: string, expression: AerospikeExp, expected: any) { const ops = [ exp.operations.write(bin, expression, exp.expWriteFlags.DEFAULT) ] await client.operate(key, ops) const result: any = await client.get(key) expect(expected).to.eql(result.bins[bin]) } const hllCats: Buffer = Buffer.from([0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) const record = { c_example: { book: [{'title': 'abc', 'price': 1.48}, {'title': 'def', 'price': 2.78}] }, floatMap: {a: 1.5, b: 3.0, c: 4.5}, floatList: [2.4, 4.8, 7.2], // n=nested nFloatList: [[2.4, 4.8, 7.2]], // dn=doubleNested dnFloatList: [[[2.4, 4.8, 7.2]]], intList: [2, 4, 6], nIntList: [[2, 4, 6]], dnIntList: [[[2, 4, 6]]], strList: ['bob', 'tom', 'harry'], nStrList: [['bob', 'tom', 'harry']], dnStrList: [[['bob', 'tom', 'harry']]], blobList: [Buffer.from('bob'), Buffer.from('tom'), Buffer.from('harry')], nBlobList: [[Buffer.from('bob'), Buffer.from('tom'), Buffer.from('harry')]], dnBlobList: [[[Buffer.from('bob'), Buffer.from('tom'), Buffer.from('harry')]]], boolList: [false, true, false], nBoolList: [[false, true, false]], dnBoolList: [[[false, true, false]]], nilList: [null, null, null], geoList: [new GeoJSON.Point(50.913, 50.308), new GeoJSON.Point(0.913, 0.308), new GeoJSON.Point(0.913, 0.308)], mapList: [{a: 1}, {b: 2}, {c: 3}], listList: [[1], [2], [3]], listListList: [[[1], [2], [3]]] //boolList: [2.4, 4.8, 7.2], //nNilList: [[2.4, 4.8, 7.2]], //dnNilList: [[[2.4, 4.8, 7.2]]], } context('Positive tests', function () { context('modifyByPath', function () { context('arguments', function () { context('bin', function () { it('accepts exp.mapBin', async function () { if (helper.cluster.isVersionInRange('= 8.1.1')) { // Server 8.1.1.2 has a bug that returns invalid request this.skip() } const modExpression = exp.float(14.0) const modifyByPath = exp.modifyByPath(exp.binMap('c_example'), exp.type.MAP, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('c_example', modifyByPath, {book: 14}) }) }) context('valueTypes', function () { it('accepts exp.type.MAP', async function () { if (helper.cluster.isVersionInRange('= 8.1.1')) { // Server 8.1.1.2 has a bug that returns invalid request this.skip() } const modExpression = exp.float(14.0) const modifyByPath = exp.modifyByPath(exp.binMap('floatMap'), exp.type.MAP, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('floatMap', modifyByPath, {a: 14, b: 14, c: 14}) }) it('accepts exp.type.LIST', async function () { if (helper.cluster.isVersionInRange('= 8.1.1')) { // Server 8.1.1.2 has a bug that returns invalid request this.skip() } const modExpression = exp.float(14.0) const modifyByPath = exp.modifyByPath(exp.binList('floatList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('floatList', modifyByPath, [14, 14, 14]) }) }) context('flags', function () { context('pathModifyFlags', function () { context('DEFAULT', function () { const flags = pathModifyFlags.DEFAULT const noFailFlags = pathModifyFlags.DEFAULT | pathModifyFlags.NO_FAIL it('equals the correct numeric value', async function () { expect(flags).to.eql(0) expect(noFailFlags).to.eql(16) }) it('returns the correct value when used with operate', async function () { if (helper.cluster.isVersionInRange('= 8.1.1')) { // Server 8.1.1.2 has a bug that returns invalid request this.skip() } const modExpression = exp.float(14.0) const modifyByPath = exp.modifyByPath(exp.binMap('floatMap'), exp.type.MAP, modExpression, flags, addAllChildren) await verifyModifyByPath('floatMap', modifyByPath, {a: 14, b: 14, c: 14}) }) it('returns the correct value when used with operate and NO_FAIL', async function () { if (helper.cluster.isVersionInRange('= 8.1.1')) { // Server 8.1.1.2 has a bug that returns invalid request this.skip() } const modExpression = exp.float(14.0) const modifyByPath = exp.modifyByPath(exp.binMap('floatMap'), exp.type.MAP, modExpression, noFailFlags, addAllChildren) await verifyModifyByPath('floatMap', modifyByPath, {a: 14, b: 14, c: 14}) }) }) context('NO_FAIL', function () { it('equals the correct numeric value', async function () { expect(pathModifyFlags.NO_FAIL).to.eql(16) }) }) }) }) context('modExp', function () { it('modifies with standard expression', async function () { if (helper.cluster.isVersionInRange('= 8.1.1')) { // Server 8.1.1.2 has a bug that returns invalid request this.skip() } const modExpression = exp.float(14.0) const modifyByPath = exp.modifyByPath(exp.binMap('c_example'), exp.type.MAP, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('c_example', modifyByPath, {book: 14}) }) it('modifies with result remove expression', async function () { const modExpression = exp.resultRemove() const modifyByPath = exp.modifyByPath(exp.binMap('c_example'), exp.type.MAP, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('c_example', modifyByPath, {}) }) it('modifies with standard loop variable expression', async function () { const modExpression = exp.mul(exp.loopVarFloat(exp.loopVarPart.VALUE), exp.float(3.7)) const modifyByPath = exp.modifyByPath(exp.binList('floatList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('floatList', modifyByPath, [ 8.88, 17.76, 26.64 ]) }) it('modifies with nested loop variable expression', async function () { const modExpression = exp.mul(exp.loopVarFloat(exp.loopVarPart.VALUE), exp.float(3.7)) const modifyByPath = exp.modifyByPath(exp.binList('nFloatList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, doubleAddAllChildren) await verifyModifyByPath('nFloatList', modifyByPath, [[ 8.88, 17.76, 26.64 ]]) }) it('modifies with double nested loop variable expression', async function () { const ctx: cdt.Context = new Context().addListIndex(0).addAllChildren().addAllChildren() const modExpression = exp.mul(exp.loopVarFloat(exp.loopVarPart.VALUE), exp.float(3.7)) const modifyByPath = exp.modifyByPath(exp.binList('dnFloatList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, ctx) await verifyModifyByPath('dnFloatList', modifyByPath, [[[ 8.88, 17.76, 26.64 ]]] ) }) context('loopVar', function () { it('use loopVarFloat Expression', async function () { const modExpression = exp.cond(exp.gt(exp.loopVarFloat(exp.loopVarPart.VALUE), exp.float(3.6)), exp.float(1.0), exp.float(0.0)) const modifyByPath = exp.modifyByPath(exp.binList('floatList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('floatList', modifyByPath, [ 0.0, 1.0, 1.0 ] ) }) it('use loopVarInt Expression', async function () { const modExpression = exp.cond(exp.gt(exp.loopVarInt(exp.loopVarPart.VALUE), exp.int(2)), exp.int(1), exp.int(0)) const modifyByPath = exp.modifyByPath(exp.binList('intList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('intList', modifyByPath, [ 0, 1, 1 ] ) }) it('use loopVarStr Expression', async function () { const modExpression = exp.cond(exp.eq(exp.loopVarStr(exp.loopVarPart.VALUE), exp.str("bob")), exp.str("pass"), exp.str("fail")) const modifyByPath = exp.modifyByPath(exp.binList('strList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('strList', modifyByPath, [ "pass", "fail", "fail" ] ) }) it('use loopVarBlob Expression', async function () { const modExpression = exp.cond(exp.eq(exp.loopVarBlob(exp.loopVarPart.VALUE), exp.bytes(Buffer.from('bob'))), exp.bytes(Buffer.from('pass')), exp.bytes(Buffer.from('fail'))) const modifyByPath = exp.modifyByPath(exp.binList('blobList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('blobList', modifyByPath, [ Buffer.from('pass'), Buffer.from('fail'), Buffer.from('fail') ] ) }) it('use loopVarBool Expression', async function () { const modExpression = exp.cond(exp.eq(exp.loopVarBool(exp.loopVarPart.VALUE), exp.bool(true)), exp.bool(false), exp.bool(true)) const modifyByPath = exp.modifyByPath(exp.binList('boolList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('boolList', modifyByPath, [ true, false, true ] ) }) it('use loopVarNil Expression', async function () { const expression = exp.eq(exp.loopVarNil(exp.loopVarPart.VALUE), exp.nil()) const ctx: cdt.Context = new Context().addAllChildrenWithFilter(expression) const selectByPath = exp.selectByPath(exp.binList('nilList'), exp.type.LIST, pathSelectFlags.MAP_VALUE, ctx) await verifySelectByPath('nilList', selectByPath, [null, null, null]) }) it('use loopVarHLL Expression', async function () { Aerospike.wrapHLL(true) const ops = [ hll.add('hll' as any, [...Array(5000).keys()], 4, 4), hll.getCount('hll') ] let result: any = await client.operate(key, ops) result = await client.get(key) const hllValue: any = result.bins.hll expect(result.bins.hll).to.be.instanceOf(Aerospike.HyperLogLog) const mapHll: any = { 'a': hllValue } const selectExpression = exp.ge(exp.hll.getCount(exp.loopVarStr(exp.loopVarPart.VALUE)), exp.int(0)) const ctx: cdt.Context = new Context().addAllChildren() await client.put(key, { hllMap: mapHll }) const ops2 = [ op.selectByPath('hllMap', exp.pathSelectFlags.VALUE, ctx) ] const result2: any = await client.operate(key, ops2) expect(result2.bins.hllMap).to.eql([hllValue]) expect(result2.bins.hllMap[0]).to.be.instanceOf(Aerospike.HyperLogLog) }) it('use loopVarGeo Expression', async function () { const modExpression = exp.cond(exp.cmpGeo(exp.geo(new GeoJSON.Circle(50.913, 50.308, 4)), exp.loopVarGeoJSON(exp.loopVarPart.VALUE)), exp.bool(true), exp.bool(false)) const modifyByPath = exp.modifyByPath(exp.binList('geoList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('geoList', modifyByPath, [ true, false, false ] ) }) it('use loopVarMap Expression', async function () { const modExpression = exp.cond(exp.eq(exp.loopVarMap(exp.loopVarPart.VALUE), exp.map({b: 2})), exp.bool(false), exp.bool(true)) const modifyByPath = exp.modifyByPath(exp.binList('mapList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('mapList', modifyByPath, [ true, false, true ] ) }) it('use loopVarList Expression', async function () { const loopVar = exp.loopVarList(exp.loopVarPart.VALUE) const modExpression = exp.cond(exp.eq(loopVar, exp.list([1])), exp.bool(false), exp.bool(true)) expect(loopVar[2].intVal).to.eql(1) const modifyByPath = exp.modifyByPath(exp.binList('listList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('listList', modifyByPath, [ false, true, true ] ) }) context('loopVarPart', async function () { it('use loopVarBool Expression with loopVarPart.VALUE', async function () { const modExpression = exp.cond(exp.eq(exp.loopVarBool(exp.loopVarPart.VALUE), exp.bool(true)), exp.bool(false), exp.bool(true)) const modifyByPath = exp.modifyByPath(exp.binList('boolList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('boolList', modifyByPath, [ true, false, true ] ) }) it('use loopVarStr Expression with loopVarPart.KEY', async function () { const loopVar = exp.loopVarStr(exp.loopVarPart.KEY) expect(loopVar[2].intVal).to.eql(0) const modExpression = exp.cond(exp.eq(loopVar, exp.str('a')), exp.str('pass'), exp.str('fail')) const modifyByPath = exp.modifyByPath(exp.binMap('floatMap'), exp.type.MAP, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('floatMap', modifyByPath, { a: 'pass', b: 'fail', c: 'fail' } ) }) it('use loopVarInt Expression with loopVarPart.VALUE', async function () { const loopVar = exp.loopVarInt(exp.loopVarPart.INDEX) const modExpression = exp.cond(exp.eq(loopVar, exp.int(1)), exp.bool(true), exp.bool(false)) expect(loopVar[2].intVal).to.eql(2) const modifyByPath = exp.modifyByPath(exp.binList('listList'), exp.type.LIST, modExpression, pathModifyFlags.DEFAULT, addAllChildren) await verifyModifyByPath('listList', modifyByPath, [ false, true, false ] ) }) }) }) }) }) }) context('selectByPath', function () { context('arguments', function () { context('bin', function () { it('accepts exp.mapBin', async function () { const ctx: cdt.Context = new Context().addMapKey('book').addAllChildren().addMapKey('price') const selectByPath = exp.selectByPath(exp.binMap('c_example'), exp.type.LIST, pathSelectFlags.MAP_VALUE, ctx) await verifySelectByPath('c_example', selectByPath, [1.48, 2.78]) }) }) context('context (v8.1.2)', function () { helper.skipUnlessVersion('>= 8.1.2', this) it('Adds mapKeysIn with andFilter', async function () { const ctx = new Context() .addMapKeysIn(['a', 'c']) .addAndFilter(exp.gt(exp.loopVarFloat(exp.loopVarPart.VALUE), exp.float(3.0))) const ops = [ op.selectByPath('floatMap', exp.pathSelectFlags.MATCHING_TREE, ctx) ] const r: any = await client.operate(key, ops) expect(r.bins.floatMap).to.deep.equal({ c: 4.5 }) }) it('Adds mapKeysIn', async function () { const ctx = new Context().addMapKeysIn(['a', 'c']); const ops = [ op.selectByPath('floatMap', exp.pathSelectFlags.MAP_VALUE, ctx) ]; const r: any = await client.operate(key, ops) const actual = r['bins']['floatMap'] // expect(actual).to.equal([1.5, 4.5]) fails, but manually // testing individual elements works. expect(actual[0]).to.equal(1.5) expect(actual[1]).to.equal(4.5) }) }) context('context', function() { it('Adds addAllChildren', async function () { const selectByPath = exp.selectByPath(exp.binList('floatList'), exp.type.LIST, pathSelectFlags.VALUE, addAllChildren) await verifySelectByPath('floatList', selectByPath, record.floatList) }) it('Adds addAllChildren twice', async function () { const selectByPath = exp.selectByPath(exp.binList('nFloatList'), exp.type.LIST, pathSelectFlags.VALUE, doubleAddAllChildren) await verifySelectByPath('nFloatList', selectByPath, record.nFloatList[0]) }) it('Adds addAllChildren with nested value', async function () { const ctx: cdt.Context = new Context().addListIndex(0).addAllChildren() const selectByPath = exp.selectByPath(exp.binList('dnFloatList'), exp.type.LIST, pathSelectFlags.VALUE, ctx) await verifySelectByPath('dnFloatList', selectByPath, record.dnFloatList[0]) }) it('Adds addAllChildren with filter', async function () { const ctx: cdt.Context = new Context().addListIndex(0).addAllChildrenWithFilter(exp.eq(exp.bool(true), exp.bool(true))) const selectByPath = exp.selectByPath(exp.binList('dnFloatList'), exp.type.LIST, pathSelectFlags.VALUE, ctx) await verifySelectByPath('dnFloatList', selectByPath, record.dnFloatList[0]) }) it('Adds addAllChildren with filter that evaluates to false', async function () { const ctx: cdt.Context = new Context().addListIndex(0).addAllChildrenWithFilter(exp.eq(exp.bool(true), exp.bool(false))) const selectByPath = exp.selectByPath(exp.binList('dnFloatList'), exp.type.LIST, pathSelectFlags.VALUE, ctx) await verifySelectByPath('dnFloatList', selectByPath, []) }) }) context('valueTypes', function () { it('accepts exp.type.LIST', async function () { const selectByPath = exp.selectByPath(exp.binList('floatList'), exp.type.LIST, pathSelectFlags.VALUE, addAllChildren) await verifySelectByPath('floatList', selectByPath, record.floatList) }) it('accepts exp.type.MAP', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.MAP, pathSelectFlags.MATCHING_TREE, addAllChildren) await verifySelectByPath('floatMap', selectByPath, record.floatMap) }) }) context('flags', function () { context('pathSelectFlags', function () { context('MATCHING_TREE', function () { const flags = pathSelectFlags.MATCHING_TREE const noFailFlags = pathSelectFlags.MATCHING_TREE | pathSelectFlags.NO_FAIL it('equals the correct numeric value', async function () { expect(flags).to.eql(0) expect(noFailFlags).to.eql(16) }) it('returns the correct value when used with operate', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.MAP, flags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, record.floatMap) }) it('returns the correct value when used with operate and NO_FAIL', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.MAP, noFailFlags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, record.floatMap) }) }) context('VALUE', function () { const flags = pathSelectFlags.VALUE const noFailFlags = pathSelectFlags.VALUE | pathSelectFlags.NO_FAIL it('equals the correct numeric value', async function () { expect(flags).to.eql(1) expect(noFailFlags).to.eql(17) }) it('returns the correct value when used with operate', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, flags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, Object.values(record.floatMap)) }) it('returns the correct value when used with operate and NO_FAIL', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, noFailFlags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, Object.values(record.floatMap)) }) }) context('LIST_VALUE', function () { const flags = pathSelectFlags.LIST_VALUE const noFailFlags = pathSelectFlags.LIST_VALUE | pathSelectFlags.NO_FAIL it('equals the correct numeric value', async function () { expect(flags).to.eql(1) expect(noFailFlags).to.eql(17) }) it('returns the correct value when used with operate', async function () { const selectByPath = exp.selectByPath(exp.binList('nFloatList'), exp.type.LIST, flags, addAllChildren) await verifySelectByPath('nFloatList', selectByPath, record.nFloatList) }) it('returns the correct value when used with operate and NO_FAIL', async function () { const selectByPath = exp.selectByPath(exp.binList('nFloatList'), exp.type.LIST, noFailFlags, addAllChildren) await verifySelectByPath('nFloatList', selectByPath, record.nFloatList) }) }) context('MAP_VALUE', function () { const flags = pathSelectFlags.MAP_VALUE const noFailFlags = pathSelectFlags.MAP_VALUE | pathSelectFlags.NO_FAIL it('returns the correct value when used with operate', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, flags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, Object.values(record.floatMap)) }) it('returns the correct value when used with operate and NO_FAIL', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, noFailFlags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, Object.values(record.floatMap)) }) }) context('MAP_KEY', function () { const flags = pathSelectFlags.MAP_KEY const noFailFlags = pathSelectFlags.MAP_KEY | pathSelectFlags.NO_FAIL it('equals the correct numeric value', async function () { expect(flags).to.eql(2) expect(noFailFlags).to.eql(18) }) it('returns the correct value when used with operate', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, flags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, Object.keys(record.floatMap)) }) it('returns the correct value when used with operate and NO_FAIL', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, noFailFlags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, Object.keys(record.floatMap)) }) }) context('MAP_KEY_VALUE', function () { const flags = pathSelectFlags.MAP_KEY_VALUE const noFailFlags = pathSelectFlags.MAP_KEY_VALUE | pathSelectFlags.NO_FAIL it('equals the correct numeric value', async function () { expect(flags).to.eql(3) expect(noFailFlags).to.eql(19) }) it('returns the correct value when used with operate', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, flags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, Object.entries(record.floatMap).flat()) }) it('returns the correct value when used with operate and NO_FAIL', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, noFailFlags, addAllChildren) await verifySelectByPath('floatMap', selectByPath, Object.entries(record.floatMap).flat()) }) }) context('NO_FAIL', function () { it('equals the correct numeric value', async function () { expect(pathSelectFlags.NO_FAIL).to.eql(16) }) }) }) }) }) }) }) context('Negative tests', function () { context('selectByPath', function () { context('arguments', function () { context('bin', function () { //const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, noFailFlags, addAllChildren) it('Does not accept non-string values', async function () { try{ const selectByPath = exp.selectByPath(2 as any, exp.type.LIST, exp.pathSelectFlags.MATCHING_TREE, addAllChildren) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("bin is not iterable") } }) }) context('valueType', function () { it('Does not accept non-number values', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), null as any, exp.pathSelectFlags.MATCHING_TREE, addAllChildren) try{ await verifySelectByPath('floatMap', selectByPath, null) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("Operations array invalid") } }) }) context('pathSelectFlags', function () { it('Does not accept non-number values', async function () { const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, null as any, addAllChildren) try{ await verifySelectByPath('floatMap', selectByPath, null) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("Operations array invalid") } }) }) context('context', function () { it('Does not accept non-number values', async function () { try{ const selectByPath = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, exp.pathSelectFlags.MATCHING_TREE, null as any) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("ctx must be a CDT Context") } }) }) }) }) context('modifyByPath', function () { context('arguments', function () { context('bin', function () { it('Does not accept non-string values', async function () { try{ const modifyByPath = exp.modifyByPath(2 as any, exp.type.LIST, exp.float(14.0), exp.pathModifyFlags.DEFAULT, addAllChildren) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("bin is not iterable") expect(error instanceof TypeError).to.eql(true) } }) }) context('valueType', function () { it('Does not accept non-number values', async function () { const modifyByPath = exp.modifyByPath(exp.binMap('floatMap'), null as any, exp.float(14.0), exp.pathModifyFlags.DEFAULT, addAllChildren) try{ await verifyModifyByPath('floatMap', modifyByPath, null) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("Operations array invalid") } }) }) context('modExp', function () { it('Does not accept non-number values', async function () { const modifyByPath = exp.modifyByPath(exp.binMap('floatMap'), exp.type.LIST, null as any, exp.pathModifyFlags.DEFAULT, addAllChildren) try{ await verifyModifyByPath('floatMap', modifyByPath, null) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("Operations array invalid") } }) }) context('pathModifyFlags', function () { it('Does not accept non-number values', async function () { try{ const modifyByPath = exp.modifyByPath(exp.binMap('floatMap'), exp.type.LIST, exp.float(14.0), null as any, addAllChildren) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("flags must be a number") } }) }) context('context', function () { it('Does not accept non-number values', async function () { try{ const modifyByPath = exp.modifyByPath(exp.binMap('floatMap'), exp.type.LIST, exp.float(14.0), exp.pathModifyFlags.DEFAULT, null as any) assert.fail("An error should have been caught!") } catch(error: any){ expect(error.message).to.eql("ctx must be a CDT Context") } }) }) }) }) }) context('Typescript', function () { it('selectByPath', function () { const selectByPath: AerospikeExp = exp.selectByPath(exp.binMap('floatMap'), exp.type.LIST, exp.pathSelectFlags.MATCHING_TREE, addAllChildren) }) it('modifyByPath', function () { const modifyByPath: AerospikeExp = exp.modifyByPath(exp.binMap('floatMap'), exp.type.LIST, exp.float(14.0), exp.pathModifyFlags.DEFAULT, addAllChildren) }) }) beforeEach(async () => { /* setup */ await client.put(key, record) }) afterEach(async () => { /* setup */ await client.remove(key) }) })