diff --git a/cdt_list.go b/cdt_list.go index 865c69c4..e41e2fb4 100644 --- a/cdt_list.go +++ b/cdt_list.go @@ -14,7 +14,7 @@ package aerospike -// List operations support negative indexing. If the index is negative, the +// List operations support negative indexing. If the index is negative, the // resolved index starts backwards from end of list. If an index is out of bounds, // a parameter error will be returned. If a range is partially out of bounds, the // valid part of the range will be returned. Index/Range examples: @@ -29,7 +29,7 @@ package aerospike // Index -3 Count 3: Last three items in list. // Index -5 Count 4: Range between fifth to last item to second to last item inclusive. // -// Nested CDT operations are supported by optional Ctx context arguments. Examples: +// Nested CDT operations are supported by optional Ctx context arguments. Examples: // // bin = [[7,9,5],[1,2,3],[6,5,4,1]] // Append 11 to last list. @@ -151,10 +151,10 @@ const ( // ListReturnTypeExists returns true if count > 0. ListReturnTypeExists ListReturnType = 13 - // ListReturnTypeInverted will invert meaning of list command and return values. For example: + // ListReturnTypeInverted will invert meaning of list command and return values. For example: // ListOperation.getByIndexRange(binName, index, count, ListReturnType.INDEX | ListReturnType.INVERTED) // With the INVERTED flag enabled, the items outside of the specified index range will be returned. - // The meaning of the list command can also be inverted. For example: + // The meaning of the list command can also be inverted. For example: // ListOperation.removeByIndexRange(binName, index, count, ListReturnType.INDEX | ListReturnType.INVERTED); // With the INVERTED flag enabled, the items outside of the specified index range will be removed and returned. ListReturnTypeInverted ListReturnType = 0x10000 @@ -180,7 +180,7 @@ const ( ListWriteFlagsDefault = 0 // ListWriteFlagsAddUnique means: Only add unique values. ListWriteFlagsAddUnique = 1 - // ListWriteFlagsInsertBounded means: Enforce list boundaries when inserting. Do not allow values to be inserted + // ListWriteFlagsInsertBounded means: Enforce list boundaries when inserting. Do not allow values to be inserted // at index outside current list boundaries. ListWriteFlagsInsertBounded = 2 // ListWriteFlagsNoFail means: do not raise error if a list item fails due to write flag constraints. @@ -425,7 +425,7 @@ func cdtListOrderFlag(order ListOrderType, pad bool) int { // ListCreateOp creates list create operation. // Server creates list at given context level. The context is allowed to be beyond list -// boundaries only if pad is set to true. In that case, nil list entries will be inserted to +// boundaries only if pad is set to true. In that case, nil list entries will be inserted to // satisfy the context position. func ListCreateOp(binName string, listOrder ListOrderType, pad bool, ctx ...*CDTContext) *Operation { // If context not defined, the set order for top-level bin list. @@ -435,12 +435,41 @@ func ListCreateOp(binName string, listOrder ListOrderType, pad bool, ctx ...*CDT return &Operation{opType: _CDT_MODIFY, ctx: ctx, binName: binName, binValue: ListValue{_CDT_LIST_SET_TYPE, cdtListOrderFlag(listOrder, pad), IntegerValue(listOrder)}, encoder: cdtCreateOpEncoder} } +// ListCreateOp creates list create operation with a persisted 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. +// +// Server creates list at given context level. The context is allowed to be beyond list +// boundaries only if pad is set to true. In that case, nil list entries will be inserted to +// satisfy the context position. +func ListCreateWithIndexOp(binName string, listOrder ListOrderType, pad bool, ctx ...*CDTContext) *Operation { + // If context not defined, the set order for top-level bin list. + if len(ctx) == 0 { + return ListSetOrderWithIndexOp(binName, listOrder) + } + + // Create nested list. persistIndex does not apply here, so ignore it. + return &Operation{opType: _CDT_MODIFY, ctx: ctx, binName: binName, binValue: ListValue{_CDT_LIST_SET_TYPE, cdtListOrderFlag(listOrder, pad), IntegerValue(listOrder)}, encoder: cdtCreateOpEncoder} +} + // ListSetOrderOp creates a set list order operation. -// Server sets list order. Server returns nil. +// Server sets list order. Server returns nil. func ListSetOrderOp(binName string, listOrder ListOrderType, ctx ...*CDTContext) *Operation { return &Operation{opType: _CDT_MODIFY, ctx: ctx, binName: binName, binValue: ListValue{_CDT_LIST_SET_TYPE, IntegerValue(listOrder)}, encoder: listGenericOpEncoder} } +// ListSetOrderWithIndexOp creates a set list order operation with a persisted 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. +// +// Server sets list order. Server returns nil. +func ListSetOrderWithIndexOp(binName string, listOrder ListOrderType, ctx ...*CDTContext) *Operation { + listOrder |= 0x10 + return &Operation{opType: _CDT_MODIFY, ctx: ctx, binName: binName, binValue: ListValue{_CDT_LIST_SET_TYPE, IntegerValue(listOrder)}, encoder: listGenericOpEncoder} +} + // ListAppendOp creates a list append operation. // Server appends values to end of list bin. // Server returns list size on bin name. diff --git a/cdt_list_test.go b/cdt_list_test.go index cfa7e16c..8a9a1611 100644 --- a/cdt_list_test.go +++ b/cdt_list_test.go @@ -74,6 +74,19 @@ var _ = gg.Describe("CDT List Test", func() { gm.Expect(sz.Bins[cdtBinName]).To(gm.Equal(100 * 2)) }) + gg.It("should create a valid CDT List with persisted index", func() { + cdtBinName := "indexedList" + cdtList, err := client.Operate(wpolicy, key, + as.ListCreateWithIndexOp(cdtBinName, as.ListOrderOrdered, false), + as.ListAppendWithPolicyOp(as.DefaultListPolicy(), cdtBinName, 1, 2, 3, 4), + as.GetBinOp(cdtBinName), + ) + gm.Expect(err).ToNot(gm.HaveOccurred()) + gm.Expect(cdtList).ToNot(gm.BeNil()) + gm.Expect(cdtList.Bins).ToNot(gm.BeNil()) + gm.Expect(cdtList.Bins[cdtBinName]).To(gm.Equal([]interface{}{4, []interface{}{1, 2, 3, 4}})) + }) + gg.Describe("CDT List Operations", func() { const listSize = 10