// *****************************************************************************
// 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.
// *****************************************************************************
const as = require('bindings')('aerospike.node')
const exp = as.exp
const lists = as.lists
const cdtCtx = require('./cdt_context')
const _valueExp = (op, valName) => (value) => [{ op, [valName]: value }]
const _int = _valueExp(exp.ops.VAL_INT, 'intVal')
const _rtype = _valueExp(exp.ops.VAL_RTYPE, 'intVal')
/*********************************************************************************
* LIST READ EXPRESSIONS
*********************************************************************************/
function getListType (type, returnType, isMulti) {
let expected = type
switch (returnType & ~lists.returnType.INVERTED) {
case lists.returnType.INDEX:
case lists.returnType.REVERSE_INDEX:
case lists.returnType.RANK:
case lists.returnType.REVERSE_RANK:
expected = isMulti ? exp.type.LIST : exp.type.INT
break
case lists.returnType.COUNT:
expected = exp.type.INT
break
case lists.returnType.VALUE:
if (isMulti) {
expected = exp.type.LIST
}
break
case lists.returnType.NONE:
default:
throw new TypeError('either set the value type as auto or match with return object data type')
}
if (type === exp.type.AUTO || type === expected) {
return expected
}
throw new TypeError('either set the value type as auto or match with return object data type')
}
const _listRead = (type, returnType, isMulti) => [
{ op: exp.ops.CALL, count: 5 },
..._rtype(getListType(type, returnType, isMulti)),
..._int(exp.sys.CALL_CDT)
]
const _listModify = (ctx, policy, op, param, extraParam) => [
{ op: exp.ops.CALL, count: 5 },
..._rtype(cdtCtx.getContextType(ctx, exp.type.LIST)),
..._int(exp.sys.CALL_CDT | exp.sys.FLAG_MODIFY_LOCAL),
{ op: exp.ops.CALL_VOP_START, count: 1 + param + (policy ? extraParam : 0), ctx },
..._int(op)
]
const _listStart = (ctx, op, param) => [
{ op: exp.ops.CALL_VOP_START, count: 1 + param, ctx },
..._int(op)
]
/**
* @module aerospike/exp/lists
*
* @description The {@link module:aerospike/exp/lists|aerospike/exp/lists} module defines functions
* for expressions on the List datatype.
*/
module.exports = {
/**
* Create expression that returns list size.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {Object} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (integer expression)
*/
size: (bin, ctx = null) => [
..._listRead(exp.type.AUTO, lists.returnType.COUNT, false),
..._listStart(ctx, lists.opcodes.SIZE, 0),
...bin
],
/**
* Create expression that selects list items identified by value and returns selected
* data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value Value expression.
* @param {AerospikeExp} returnType Return type.
* @param {Object} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByValue: (bin, value, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_ALL_BY_VALUE, 2),
..._int(returnType),
...value,
...bin
],
/**
* Create expression that selects list items identified by value range and returns selected
* data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} end End value expression.
* @param {AerospikeExp} begin Begin value expression.
* @param {AerospikeExp} returnType Return type.
* @param {Object} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByValueRange: (bin, begin, end, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_BY_VALUE_INTERVAL, 3),
..._int(returnType),
...begin,
...end,
...bin
],
/**
* Create expression that selects list items identified by values and returns selected
* data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value Values list expression.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByValueList: (bin, value, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_BY_VALUE_LIST, 2),
..._int(returnType),
...value,
...bin
],
/**
* Create expression that selects list items nearest to value and greater by relative rank
* and returns selected data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} value Values list expression.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByRelRankRangeToEnd: (bin, value, rank, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_BY_VALUE_REL_RANK_RANGE, 3),
..._int(returnType),
...value,
...rank,
...bin
],
/**
* Create expression that selects list items nearest to value and greater by relative rank with a
* count limit and returns selected data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value Values list expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} count Count integer expression.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByRelRankRange: (bin, value, rank, count, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_BY_VALUE_REL_RANK_RANGE, 4),
..._int(returnType),
...value,
...rank,
...count,
...bin
],
/**
* Create expression that selects list item identified by index
* and returns selected data specified by returnType.
*
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {AerospikeExp} valueType expression value type.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (valueType expression)
*/
getByIndex: (bin, index, valueType, returnType, ctx = null) => [
..._listRead(valueType, returnType, false),
..._listStart(ctx, lists.opcodes.GET_BY_INDEX, 2),
..._int(returnType),
...index,
...bin
],
/**
* Create expression that selects list items starting at specified index to the end of list
* and returns selected data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByIndexRangeToEnd: (bin, index, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_BY_INDEX_RANGE, 2),
..._int(returnType),
...index,
...bin
],
/**
* Create expression that selects "count" list items starting at specified index
* and returns selected data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} count Count integer expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByIndexRange: (bin, index, count, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_BY_INDEX_RANGE, 3),
..._int(returnType),
...index,
...count,
...bin
],
/**
* Create expression that selects list item identified by rank
* and returns selected data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} valueType expression value type.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (valueType expression)
*/
getByRank: (bin, rank, valueType, returnType, ctx = null) => [
..._listRead(valueType, returnType, false),
..._listStart(ctx, lists.opcodes.GET_BY_RANK, 2),
..._int(returnType),
...rank,
...bin
],
/**
* Create expression that selects list items starting at specified rank to the last ranked item
* and returns selected data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByRankRangeToEnd: (bin, rank, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_BY_RANK_RANGE, 2),
..._int(returnType),
...rank,
...bin
],
/**
* Create expression that selects "count" list items starting at specified rank
* and returns selected data specified by returnType.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} count Count integer expression.
* @param {AerospikeExp} returnType Return type.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (expression)
*/
getByRankRange: (bin, rank, count, returnType, ctx = null) => [
..._listRead(exp.type.AUTO, returnType, true),
..._listStart(ctx, lists.opcodes.GET_BY_RANK_RANGE, 3),
..._int(returnType),
...rank,
...count,
...bin
],
/*********************************************************************************
* LIST MODIFY EXPRESSIONS
*********************************************************************************/
/**
* Create expression that appends value to end of list.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value Value expression.
* @param {Object} policy Optional list write policy.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
append: (bin, value, policy = null, ctx = null) => [
..._listModify(ctx, policy, lists.opcodes.APPEND, 1, 2),
...value,
{ op: exp.ops.CDT_LIST_CRMOD, listPolicy: policy },
...bin
],
/**
* Create expression that appends list items to end of list.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value List items expression.
* @param {Object} policy Optional list write policy.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
appendItems: (bin, value, policy = null, ctx = null) => [
..._listModify(ctx, policy, lists.opcodes.APPEND_ITEMS, 1, 2),
...value,
{ op: exp.ops.CDT_LIST_CRMOD, listPolicy: policy },
...bin
],
/**
* Create expression that inserts value to specified index of list.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value Value expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {Object} policy Optional list write policy.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
insert: (bin, value, idx, policy = null, ctx = null) => [
..._listModify(ctx, policy, lists.opcodes.INSERT, 2, 1),
...idx,
...value,
{ op: exp.ops.CDT_LIST_CRMOD, listPolicy: policy },
...bin
],
/**
* Create expression that inserts each input list item starting at specified index of list.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value List items expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {Object} policy Optional list write policy.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
insertItems: (bin, value, idx, policy = null, ctx = null) => [
..._listModify(ctx, policy, lists.opcodes.INSERT_ITEMS, 2, 1),
...idx,
...value,
{ op: exp.ops.CDT_LIST_CRMOD, listPolicy: policy },
...bin
],
/**
* Create expression that increments list[index] by value.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value Value expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {Object} policy Optional list write policy.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
increment: (bin, value, idx, policy = null, ctx = null) => [
..._listModify(ctx, policy, lists.opcodes.INCREMENT, 2, 2),
...idx,
...value,
{ op: exp.ops.CDT_LIST_CRMOD, listPolicy: policy },
...bin
],
/**
* Create expression that sets item value at specified index in list.
*
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value Value expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {Object} policy Optional list write policy.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
set: (bin, value, idx, policy = null, ctx = null) => [
..._listModify(ctx, policy, lists.opcodes.SET, 2, 1),
...idx,
...value,
{ op: exp.ops.CDT_LIST_CRMOD, listPolicy: policy },
...bin
],
/**
* Create expression that removes all items in list.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
clear: (bin, ctx = null) => [
..._listModify(ctx, null, lists.opcodes.CLEAR, 0, 0),
...bin
],
/**
* Create expression that sorts list.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {number} order Sort order flags.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
sort: (bin, order, ctx = null) => [
..._listModify(ctx, null, lists.opcodes.SORT, 1, 0),
..._int(order),
...bin
],
/**
* Create expression that removes list items identified by value.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} value Value expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByValue: (bin, value, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_ALL_BY_VALUE, 2, 0),
..._int(lists.returnType.NONE),
...value,
...bin
],
/**
* Create expression that removes list items identified by values.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} values Values list expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByValueList: (bin, values, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_VALUE_LIST, 2, 0),
..._int(lists.returnType.NONE),
...values,
...bin
],
/**
* Create expression that removes list items identified by value range
* (begin inclusive, end exclusive). If begin is nil, the range is less than end.
* If end is infinity, the range is greater than equal to begin.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} end End value expression.
* @param {AerospikeExp} begin Begin value expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByValueRange: (bin, end, begin, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_VALUE_INTERVAL, 3, 0),
..._int(lists.returnType.NONE),
...begin,
...end,
...bin
],
/**
* Create expression that removes list items nearest to value and greater by relative rank.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} value Value expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByRelRankRangeToEnd: (bin, rank, value, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_VALUE_REL_RANK_RANGE, 3, 0),
..._int(lists.returnType.NONE),
...value,
...rank,
...bin
],
/**
* Create expression that removes list items nearest to value and greater by relative rank with a
* count limit.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} count Count integer expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} value Value expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByRelRankRange: (bin, count, rank, value, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_VALUE_REL_RANK_RANGE, 4, 0),
..._int(lists.returnType.NONE),
...value,
...rank,
...count,
...bin
],
/**
* Create expression that removes list item identified by index.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByIndex: (bin, idx, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_INDEX, 2, 0),
..._int(lists.returnType.NONE),
...idx,
...bin
],
/**
* Create expression that removes list items starting at specified index to the end of list.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByIndexRangeToEnd: (bin, idx, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_INDEX_RANGE, 2, 0),
..._int(lists.returnType.NONE),
...idx,
...bin
],
/**
* Create expression that removes "count" list items starting at specified index.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} count Count integer expression.
* @param {AerospikeExp} idx Index integer expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByIndexRange: (bin, count, idx, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_INDEX_RANGE, 3, 0),
..._int(lists.returnType.NONE),
...idx,
...count,
...bin
],
/**
* Create expression that removes list item identified by rank.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByRank: (bin, rank, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_RANK, 2, 0),
..._int(lists.returnType.NONE),
...rank,
...bin
],
/**
* Create expression that removes list items starting at specified rank to the last ranked item.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByRankRangeToEnd: (bin, rank, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_RANK_RANGE, 2, 0),
..._int(lists.returnType.NONE),
...rank,
...bin
],
/**
* Create expression that removes "count" list items starting at specified rank.
*
* @param {AerospikeExp} bin List bin or list value expression.
* @param {AerospikeExp} count Count integer expression.
* @param {AerospikeExp} rank Rank integer expression.
* @param {AerospikeExp} ctx Optional context path for nested CDT.
* @return {AerospikeExp} (list expression)
*/
removeByRankRange: (bin, count, rank, ctx = null, returnType = lists.returnType.NONE) => [
..._listModify(ctx, null, lists.opcodes.REMOVE_BY_RANK_RANGE, 3, 0),
..._int(lists.returnType.NONE),
...rank,
...count,
...bin
]
}