aerospike
Version:
Aerospike Client Library
890 lines (593 loc) • 34.6 kB
text/typescript
// *****************************************************************************
// 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.
// *****************************************************************************
/* 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)
})
})