diff --git a/lib/exp.js b/lib/exp.js index 44bd93ef6..b6a853719 100644 --- a/lib/exp.js +++ b/lib/exp.js @@ -208,6 +208,22 @@ exports.geo = _valueExp(exp.ops.VAL_GEO, 'value') */ exports.nil = () => [{ op: exp.ops.AS_VAL, value: null }] +/** + * Create 'inf' value. + * + * @function + * @return {AerospikeExp} + */ +exports.inf = () => [{ op: exp.ops.AS_VAL, inf: null }] + +/** + * Create 'wildcard' value. + * + * @function + * @return {AerospikeExp} + */ +exports.wildcard = () => [{ op: exp.ops.AS_VAL, wildcard: null }] + const _val = _valueExp(exp.ops.AS_VAL, 'value') /** diff --git a/src/include/conversions.h b/src/include/conversions.h index ce44183a7..380f49502 100644 --- a/src/include/conversions.h +++ b/src/include/conversions.h @@ -73,6 +73,8 @@ int get_uint64_property(uint64_t *intp, v8::Local obj, char const *prop, const LogInfo *log); int get_uint32_property(uint32_t *intp, v8::Local obj, char const *prop, const LogInfo *log); +void get_inf_property(as_val **value, const LogInfo *log); +void get_wildcard_property(as_val **value, const LogInfo *log); int get_asval_property(as_val **value, v8::Local obj, const char *prop, const LogInfo *log); int get_string_property(char **strp, v8::Local obj, diff --git a/src/main/expressions.cc b/src/main/expressions.cc index d138d58bb..11626e96f 100644 --- a/src/main/expressions.cc +++ b/src/main/expressions.cc @@ -201,6 +201,16 @@ int convert_entry(Local entry_obj, as_exp_entry *entry, return AS_NODE_PARAM_OK; } + if (Nan::Has(entry_obj, Nan::New("inf").ToLocalChecked()).FromJust()) { + entry->v.val = NULL; + get_inf_property(&entry->v.val, log); + } + + if (Nan::Has(entry_obj, Nan::New("wildcard").ToLocalChecked()).FromJust()) { + entry->v.val = NULL; + get_wildcard_property(&entry->v.val, log); + } + return rc; } diff --git a/src/main/util/conversions.cc b/src/main/util/conversions.cc index 11e603f7b..1b8d85b49 100644 --- a/src/main/util/conversions.cc +++ b/src/main/util/conversions.cc @@ -420,6 +420,18 @@ int get_optional_bytes_property(uint8_t **bytes, int *size, bool *defined, return AS_NODE_PARAM_OK; } +void get_inf_property(as_val **value, const LogInfo *log) +{ + Nan::HandleScope scope; + *value = (as_val *)&as_cmp_inf; +} + +void get_wildcard_property(as_val **value, const LogInfo *log) +{ + Nan::HandleScope scope; + *value = (as_val *)&as_cmp_wildcard; +} + int get_asval_property(as_val **value, Local obj, const char *prop, const LogInfo *log) { diff --git a/test/exp.js b/test/exp.js index e606fb5b2..b229a6456 100644 --- a/test/exp.js +++ b/test/exp.js @@ -22,6 +22,7 @@ const Aerospike = require('../lib/aerospike') const exp = Aerospike.exp const op = Aerospike.operations +const maps = Aerospike.maps const GeoJSON = Aerospike.GeoJSON @@ -236,6 +237,34 @@ describe('Aerospike.exp', function () { }) }) + describe('nil', function () { + it('evaluates to true if any expression evaluates to true', async function () { + const key = await createRecord({ tags: { a: 'blue', b: 'green', c: 'yellow' } }) + + await testNoMatch(key, exp.eq(exp.maps.getByValueRange(exp.binMap('tags'), exp.str('green'), exp.nil(), maps.returnType.COUNT), exp.int(2))) + await testMatch(key, exp.eq(exp.maps.getByValueRange(exp.binMap('tags'), exp.str('green'), exp.nil(), maps.returnType.COUNT), exp.int(1))) + }) + }) + + describe('inf', function () { + it('evaluates to true if any expression evaluates to true', async function () { + const key = await createRecord({ tags: { a: 'blue', b: 'green', c: 'yellow' } }) + + await testNoMatch(key, exp.eq(exp.maps.getByValueRange(exp.binMap('tags'), exp.inf(), exp.str('green'), maps.returnType.COUNT), exp.int(1))) + await testMatch(key, exp.eq(exp.maps.getByValueRange(exp.binMap('tags'), exp.inf(), exp.str('green'), maps.returnType.COUNT), exp.int(2))) + }) + + }) + + describe('wildcard', function () { + it('evaluates to true if any expression evaluates to true', async function () { + const key = await createRecord({ tags: { a: 'blue', b: 'green', c: 'yellow' } }) + + await testNoMatch(key, exp.eq(exp.maps.getByValueRange(exp.binMap('tags'), exp.inf(), exp.wildcard(), maps.returnType.COUNT), exp.int(2))) + await testMatch(key, exp.eq(exp.maps.getByValueRange(exp.binMap('tags'), exp.inf(), exp.wildcard(), maps.returnType.COUNT), exp.int(3))) + }) + }) + describe('arithmetic expressions', function () { describe('int bin add expression', function () { it('evaluates exp_read op to true if temp bin equals the sum of bin and given value', async function () {