Skip to content

Commit

Permalink
Added persistent list indexes
Browse files Browse the repository at this point in the history
CLIENT-2770
CLIENT-2773
Added additional status to status.js
  • Loading branch information
DomPeliniAerospike committed Feb 14, 2024
1 parent 6041d5a commit f71fc61
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 1 deletion.
55 changes: 55 additions & 0 deletions lib/lists.js
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,61 @@ exports.clear = function (bin) {
return new ListOperation(opcodes.LIST_CLEAR, bin)
}

/**
* @summary Creates map create operation.
*
*
* @param {string} bin - bin name.
* @param {number} order - list order.
* @parm {boolean} pad - If true, the context is allowed to be beyond list boundaries. In that case, nil
* list entries will be inserted to satisfy the context position.
* @param {boolean} persistIndex - If true, persist list index. A list index improves lookup performance,
* but requires more storage. A list index can be created for a top-level ordered list only. Nested and
* unordered list indexes are not supported.
* @param {number} ctx - optional path to nested list. If not defined, the top-level list is used.
*
* @returns {Object} Operation that can be passed to the {@link Client#operate} command.
*
* @example
*
* const Aerospike = require('aerospike')
* const lists = Aerospike.lists
* const key = new Aerospike.Key('test', 'demo', 'mapKey')
*
* // INSERT HOSTNAME AND PORT NUMBER OF AEROSPIKE SERVER NODE HERE!
* var config = {
* hosts: '192.168.33.10:3000',
* // Timeouts disabled, latency dependent on server location. Configure as needed.
* policies: {
* operate : new Aerospike.OperatePolicy({socketTimeout : 0, totalTimeout : 0})
* }
* }
*
* Aerospike.connect(config).then(async client => {
* let ops = [
* lists.create('list', lists.order.ORDERED, false, true)
* ]
* let result = await client.operate(key, ops)
* console.log(result.bins) // => { list: null }
* let record = await client.get(key)
* console.log(record.bins) // => { list: [] }
*
* await client.remove(key)
* client.close()
* })
*/
exports.create = function (bin, order, pad = false, persistIndex = false, ctx) {
const op = new ListOperation(opcodes.LIST_CREATE, bin)
op.order = order
op.pad = pad
op.persistIndex = persistIndex
if (ctx === undefined) {
return op
}

return op.withContext(ctx)
}

/**
* @summary Sets the list element at the specified index to a new value.
* @description This operation returns no result.
Expand Down
31 changes: 31 additions & 0 deletions lib/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,37 @@ const as = require('bindings')('aerospike.node')
* @description Database operation error codes.
*/

/**
* One or more keys failed in a batch.
* @const {number}
*/
exports.BATCH_FAILED = exports.AEROSPIKE_BATCH_FAILED = as.status.AEROSPIKE_BATCH_FAILED

/**
* No response received from server.
* @const {number}
*/
exports.NO_RESPONSE = exports.AEROSPIKE_NO_RESPONSE = as.status.AEROSPIKE_NO_RESPONSE

/**
* Max errors limit reached.
* @const {number}
*/
exports.MAX_ERROR_RATE = exports.AEROSPIKE_MAX_ERROR_RATE = as.status.AEROSPIKE_MAX_ERROR_RATE

/**
* Abort split batch retry and use normal node retry instead.
* Used internally and should not be returned to user.
* @const {number}
*/
exports.USE_NORMAL_RETRY = exports.AEROSPIKE_USE_NORMAL_RETRY = as.status.AEROSPIKE_USE_NORMAL_RETRY

/**
* Max retries limit reached.
* @const {number}
*/
exports.ERR_MAX_RETRIES_EXCEEDED = exports.AEROSPIKE_ERR_MAX_RETRIES_EXCEEDED = as.status.AEROSPIKE_ERR_MAX_RETRIES_EXCEEDED

/**
* Async command delay queue is full.
* @const {number}
Expand Down
26 changes: 25 additions & 1 deletion src/main/list_operations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,29 @@ bool add_list_increment_op(as_operations *ops, const char *bin,
return true;
}

bool add_list_create_op(as_operations *ops, const char *bin,
as_cdt_ctx *context, Local<Object> op, LogInfo *log)
{
as_list_order order;
if (get_uint32_property((uint32_t*)&order, op, "order", log) != AS_NODE_PARAM_OK) {
return false;
}

bool pad;
if (get_bool_property(&pad, op, "pad", log) != AS_NODE_PARAM_OK) {
return false;
}

bool persist_index;
if (get_bool_property(&persist_index, op, "persistIndex", log) != AS_NODE_PARAM_OK) {
return false;
}

as_v8_debug(log, "order=%i, pad=%s, persist_index=%s", order, pad ? "true" : "false", persist_index ? "true" : "false");
as_operations_list_create_all(ops, bin, context, order, pad, persist_index);
return true;
}

bool add_list_size_op(as_operations *ops, const char *bin, as_cdt_ctx *context,
Local<Object> obj, LogInfo *log)
{
Expand Down Expand Up @@ -1084,7 +1107,8 @@ const ops_table_entry ops_table[] = {
{"LIST_GET_BY_RANK", add_list_get_by_rank_op},
{"LIST_GET_BY_RANK_RANGE", add_list_get_by_rank_range_op},
{"LIST_INCREMENT", add_list_increment_op},
{"LIST_SIZE", add_list_size_op}};
{"LIST_SIZE", add_list_size_op},
{"LIST_CREATE", add_list_create_op}};

int add_list_op(as_operations *ops, uint32_t opcode, Local<Object> op,
LogInfo *log)
Expand Down
5 changes: 5 additions & 0 deletions src/main/policy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,11 @@ int batchwrite_policy_from_jsobject(as_policy_batch_write *policy,
AS_NODE_PARAM_OK) {
return rc;
}
if ((rc = get_optional_uint32_property((uint32_t *)&policy->ttl, NULL, obj,
"ttl", log)) !=
AS_NODE_PARAM_OK) {
return rc;
}
if ((rc = get_optional_bool_property(&policy->durable_delete, NULL, obj,
"durableDelete", log)) !=
AS_NODE_PARAM_OK) {
Expand Down
63 changes: 63 additions & 0 deletions test/lists.js
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,69 @@ describe('client.operate() - CDT List operations', function () {
})
})

describe('lists.create', function () {
it('creates a new list', function () {
return initState()
.then(createRecord({ list: [1, 2, 3, 4, 5] }))
.then(operate(lists.create('emptyList', lists.order.ORDERED)))
.then(assertRecordEql({ list: [1, 2, 3, 4, 5], emptyList: [] }))
.then(cleanup)
})

it('creates a new list with persist index true', function () {
return initState()
.then(createRecord({ list: [1, 2, 3, 4, 5] }))
.then(operate(lists.create('emptyList', lists.order.ORDERED, false, true)))
.then(assertRecordEql({ list: [1, 2, 3, 4, 5], emptyList: [] }))
.then(cleanup)
})


it('creates a new list with persist index true and pad true', function () {
return initState()
.then(createRecord({ list: [1, 2, 3, 4, 5] }))
.then(operate(lists.create('emptyList', lists.order.ORDERED, true, true)))
.then(assertRecordEql({ list: [1, 2, 3, 4, 5], emptyList: [] }))
.then(cleanup)
})

it('creates a new list with pad true', function () {
return initState()
.then(createRecord({ list: [1, 2, 3, 4, 5] }))
.then(operate(lists.create('emptyList', lists.order.ORDERED, true, false)))
.then(assertRecordEql({ list: [1, 2, 3, 4, 5], emptyList: [] }))
.then(cleanup)
})

context('with nested list context', function () {
helper.skipUnlessVersion('>= 4.6.0', this)

it('creates a new list within a map', function () {
return initState()
.then(createRecord({ map: { c: 1, b: 2, a: 3 } }))
.then(operate(lists.create('map', lists.order.ORDERED).withContext(ctx => ctx.addMapKeyCreate('nested'))))
.then(assertRecordEql({ map: { c: 1, b: 2, a: 3, nested: []} }))
.then(cleanup)
})

it('creates a new list within a list', function () {
return initState()
.then(createRecord({ list: [1, 2, 3, 4, 5] }))
.then(operate(lists.create('list', lists.order.UNORDERED, true, false).withContext(ctx => ctx.addListIndex(10))))
.then(assertRecordEql({ list: [1, 2, 3, 4, 5, null, null, null, null, null, []] }))
.then(cleanup)
})

it('creates a new list within a list', function () {
return initState()
.then(createRecord({ list: [1, 2, 3, 4, 5] }))
.then(operate(lists.create('list', lists.order.UNORDERED, true, true).withContext(ctx => ctx.addListIndex(10))))
.then(assertRecordEql({ list: [1, 2, 3, 4, 5, null, null, null, null, null, []] }))
.then(cleanup)
})
})
})

describe('lists.set', function () {
it('sets the item at the specified index', function () {
return initState()
Expand Down

0 comments on commit f71fc61

Please sign in to comment.