Skip to content

Commit 09f96c8

Browse files
CascadingRadiumCopilotabhinavdangeti
authored
[v17] MB-27666: Nested Fields (#70)
- Adds a `NestedDocument` interface which extends the `Document` interface, allowing users to visit any sub-documents that may be nested within the parent document. - Adds a new `NewIndexInternalID` method to create an `IndexInternalID` and also extends the API to enable getting the integer value of the `IndexInternalID` from it. - Extends the `IndexReader` interface to support the `Ancestors` method, which allows the user to fetch the ancestry chain of any document ID given. If the document does not have any ancestors (it is a root document), an ancestry chain containing only the input document is returned. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Abhinav Dangeti <abhinav@couchbase.com>
1 parent f19a6d6 commit 09f96c8

2 files changed

Lines changed: 85 additions & 1 deletion

File tree

document.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,11 @@ type SynonymDocument interface {
124124
// The provided visitor function is called for each synonym field.
125125
VisitSynonymFields(visitor SynonymFieldVisitor)
126126
}
127+
128+
// NestedDocument is a document that contains other documents inside it.
129+
type NestedDocument interface {
130+
Document
131+
// VisitNestedDocuments allows iteration over all nested documents in the document.
132+
// The provided visitor function is called for each nested document.
133+
VisitNestedDocuments(visitor func(doc Document))
134+
}

index.go

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ package index
1717
import (
1818
"bytes"
1919
"context"
20+
"encoding/binary"
21+
"fmt"
2022
"reflect"
2123
)
2224

@@ -185,17 +187,46 @@ func (tfv *TermFieldVector) Size() int {
185187
len(tfv.Field) + len(tfv.ArrayPositions)*sizeOfUint64
186188
}
187189

188-
// IndexInternalID is an opaque document identifier interal to the index impl
190+
// IndexInternalID is an opaque document identifier internal to the index impl
189191
type IndexInternalID []byte
190192

193+
// NewIndexInternalID encodes a uint64 into an 8-byte big-endian ID, reusing `buf` when possible.
194+
func NewIndexInternalID(buf []byte, in uint64) IndexInternalID {
195+
if len(buf) != 8 {
196+
if cap(buf) >= 8 {
197+
buf = buf[0:8]
198+
} else {
199+
buf = make([]byte, 8)
200+
}
201+
}
202+
binary.BigEndian.PutUint64(buf, in)
203+
return buf
204+
}
205+
206+
// NewIndexInternalIDFrom creates a new IndexInternalID by copying from `other`, reusing `buf` when possible.
207+
func NewIndexInternalIDFrom(buf IndexInternalID, other IndexInternalID) IndexInternalID {
208+
buf = buf[:0]
209+
return append(buf, other...)
210+
}
211+
212+
// Equals checks if two IndexInternalID values are equal.
191213
func (id IndexInternalID) Equals(other IndexInternalID) bool {
192214
return id.Compare(other) == 0
193215
}
194216

217+
// Compare compares two IndexInternalID values, inherently comparing the encoded uint64 values.
195218
func (id IndexInternalID) Compare(other IndexInternalID) int {
196219
return bytes.Compare(id, other)
197220
}
198221

222+
// Value returns the uint64 value encoded in the IndexInternalID.
223+
func (id IndexInternalID) Value() (uint64, error) {
224+
if len(id) != 8 {
225+
return 0, fmt.Errorf("wrong len for IndexInternalID: %q", id)
226+
}
227+
return binary.BigEndian.Uint64(id), nil
228+
}
229+
199230
type TermFieldDoc struct {
200231
Term string
201232
ID IndexInternalID
@@ -405,3 +436,48 @@ type IndexInsightsReader interface {
405436
// cluster densities (or cardinalities)
406437
CentroidCardinalities(field string, limit int, descending bool) (cenCards []CentroidCardinality, err error)
407438
}
439+
440+
// -----------------------------------------------------------------------------
441+
// NestedReader is an extended index reader that supports hierarchical document structures.
442+
type NestedReader interface {
443+
IndexReader
444+
// Ancestors returns the ancestral chain for a given document ID in the index.
445+
// For nested documents, this method retrieves all parent documents in the hierarchy
446+
// leading up to the root document ID.
447+
Ancestors(id IndexInternalID, prealloc []AncestorID) ([]AncestorID, error)
448+
}
449+
450+
// AncestorID represents the identifier of an ancestor document in an ancestor chain.
451+
type AncestorID uint64
452+
453+
// NewAncestorID creates a new AncestorID from the given uint64 value.
454+
func NewAncestorID(val uint64) AncestorID {
455+
return AncestorID(val)
456+
}
457+
458+
// Compare compares two AncestorID values.
459+
func (a AncestorID) Compare(b AncestorID) int {
460+
switch {
461+
case a < b:
462+
return -1
463+
case a > b:
464+
return 1
465+
default:
466+
return 0
467+
}
468+
}
469+
470+
// Equals checks if two AncestorID values are equal.
471+
func (a AncestorID) Equals(b AncestorID) bool {
472+
return a == b
473+
}
474+
475+
// Add returns a new AncestorID by adding the given uint64 value to the current AncestorID.
476+
func (a AncestorID) Add(n uint64) AncestorID {
477+
return AncestorID(uint64(a) + n)
478+
}
479+
480+
// ToIndexInternalID converts the AncestorID to an IndexInternalID.
481+
func (a AncestorID) ToIndexInternalID(prealloc IndexInternalID) IndexInternalID {
482+
return NewIndexInternalID(prealloc, uint64(a))
483+
}

0 commit comments

Comments
 (0)