@@ -136,10 +136,20 @@ const (
136136 jsonArrayKeyDescendingMarker = jsonTrueKeyDescendingMarker - 1
137137 jsonObjectKeyDescendingMarker = jsonArrayKeyDescendingMarker - 1
138138
139+ // LTREE key encoding markers
140+ ltreeKeyMarker = jsonEmptyArrayKeyDescendingMarker + 1
141+ ltreeKeyDescendingMarker = ltreeKeyMarker + 1
142+
139143 // Terminators for JSON Key encoding.
140144 jsonKeyTerminator byte = 0x00
141145 jsonKeyDescendingTerminator byte = 0xFF
142146
147+ // Terminators for LTREE Key encoding.
148+ ltreeKeyTerminator byte = 0x00
149+ ltreeKeyDescendingTerminator byte = 0xFF
150+ ltreeLabelKeyTerminator byte = 0x01
151+ ltreeLabelKeyDescendingTerminator byte = 0xFE
152+
143153 // IntMin is chosen such that the range of int tags does not overlap the
144154 // ascii character set that is frequently used in testing.
145155 IntMin = 0x80 // 128
@@ -863,6 +873,20 @@ func getBytesLength(b []byte, e escapes) (int, error) {
863873 }
864874}
865875
876+ // getLTreeLength finds the length of a ltree encoding.
877+ func getLTreeLength (b []byte , dir Direction ) (int , error ) {
878+ var i int
879+ if dir == Ascending {
880+ i = bytes .IndexByte (b , ltreeKeyTerminator )
881+ } else {
882+ i = bytes .IndexByte (b , ltreeKeyDescendingTerminator )
883+ }
884+ if i == - 1 {
885+ return 0 , errors .Errorf ("did not find terminator" )
886+ }
887+ return i + 1 , nil
888+ }
889+
866890// prettyPrintInvertedIndexKey returns a string representation of the path part of a JSON inverted
867891// index.
868892func prettyPrintInvertedIndexKey (b []byte ) (string , []byte , error ) {
@@ -1726,6 +1750,101 @@ func DecodeBitArrayDescending(b []byte) ([]byte, bitarray.BitArray, error) {
17261750 return b , ba , err
17271751}
17281752
1753+ // EncodeLTreeAscending encodes a ltree.T value, appends it to the
1754+ // supplied buffer, and returns the final buffer. The encoding is guaranteed to
1755+ // be ordered such that if t1 < t2 then bytes.Compare will order them the same
1756+ // way after encoding.
1757+ //
1758+ // The encoding is in the below format:
1759+ // [ ltreeMarker ]
1760+ // for each label:
1761+ //
1762+ // [ label raw bytes ] [ ltreeLabelKeyTerminator ]
1763+ //
1764+ // [ ltreeKeyTerminator ]
1765+ func EncodeLTreeAscending (b []byte , d ltree.T ) []byte {
1766+ b = append (b , ltreeKeyMarker )
1767+ d .ForEachLabel (func (i int , label string ) {
1768+ b = append (b , []byte (label )... )
1769+ b = append (b , ltreeLabelKeyTerminator )
1770+ })
1771+ b = append (b , ltreeKeyTerminator )
1772+ return b
1773+ }
1774+
1775+ // EncodeLTreeDescending is the descending version of EncodeLTreeAscending.
1776+ func EncodeLTreeDescending (b []byte , d ltree.T ) []byte {
1777+ b = append (b , ltreeKeyDescendingMarker )
1778+ d .ForEachLabel (func (i int , label string ) {
1779+ n := len (b )
1780+ b = append (b , []byte (label )... )
1781+ onesComplement (b [n :])
1782+ b = append (b , ltreeLabelKeyDescendingTerminator )
1783+ })
1784+ b = append (b , ltreeKeyDescendingTerminator )
1785+ return b
1786+ }
1787+
1788+ // DecodeLTreeAscending decodes a ltree.T value which was encoded using
1789+ // EncodeLTreeAscending. The remainder of the input buffer and the
1790+ // decoded ltree.T are returned.
1791+ func DecodeLTreeAscending (b []byte ) ([]byte , ltree.T , error ) {
1792+ if PeekType (b ) != LTree {
1793+ return nil , ltree .Empty , errors .Errorf ("did not find marker %#x" , b )
1794+ }
1795+ b = b [1 :]
1796+
1797+ var labels []string
1798+ for {
1799+ if len (b ) != 0 && b [0 ] == ltreeKeyTerminator {
1800+ b = b [1 :]
1801+ break
1802+ }
1803+ i := bytes .IndexByte (b , ltreeLabelKeyTerminator )
1804+ if i == - 1 {
1805+ return nil , ltree .Empty , errors .Errorf ("malformed ltree encoding" )
1806+ }
1807+ labels = append (labels , string (b [:i ]))
1808+ b = b [i + 1 :]
1809+ }
1810+ l , err := ltree .ParseLTreeFromLabels (labels )
1811+ if err != nil {
1812+ return nil , ltree .Empty , err
1813+ }
1814+ return b , l , nil
1815+ }
1816+
1817+ // DecodeLTreeDescending is the descending version of DecodeLTreeAscending.
1818+ func DecodeLTreeDescending (b []byte ) ([]byte , ltree.T , error ) {
1819+ if PeekType (b ) != LTreeDesc {
1820+ return nil , ltree .Empty , errors .Errorf ("did not find marker %#x" , b )
1821+ }
1822+ b = b [1 :]
1823+
1824+ var labels []string
1825+ for {
1826+ if len (b ) != 0 && b [0 ] == ltreeKeyDescendingTerminator {
1827+ b = b [1 :]
1828+ break
1829+ }
1830+ i := bytes .IndexByte (b , ltreeLabelKeyDescendingTerminator )
1831+ if i == - 1 {
1832+ return nil , ltree .Empty , errors .Errorf ("malformed ltree encoding" )
1833+ }
1834+ // Deep copying here is necessary to avoid modifying the input buffer slice.
1835+ var label []byte
1836+ label = append (label , b [:i ]... )
1837+ onesComplement (label )
1838+ labels = append (labels , string (label ))
1839+ b = b [i + 1 :]
1840+ }
1841+ l , err := ltree .ParseLTreeFromLabels (labels )
1842+ if err != nil {
1843+ return nil , ltree .Empty , err
1844+ }
1845+ return b , l , nil
1846+ }
1847+
17291848// Type represents the type of a value encoded by
17301849// Encode{Null,NotNull,Varint,Uvarint,Float,Bytes}.
17311850//
@@ -1788,6 +1907,7 @@ const (
17881907 JsonEmptyArrayDesc Type = 43
17891908 PGVector Type = 44
17901909 LTree Type = 45
1910+ LTreeDesc Type = 46
17911911)
17921912
17931913// typMap maps an encoded type byte to a decoded Type. It's got 256 slots, one
@@ -1890,6 +2010,10 @@ func slowPeekType(b []byte) Type {
18902010 return Decimal
18912011 case m == voidMarker :
18922012 return Void
2013+ case m == ltreeKeyMarker :
2014+ return LTree
2015+ case m == ltreeKeyDescendingMarker :
2016+ return LTreeDesc
18932017 }
18942018 }
18952019 return Unknown
@@ -2086,6 +2210,10 @@ func PeekLength(b []byte) (int, error) {
20862210 return 0 , errors .Errorf ("slice too short for float (%d)" , len (b ))
20872211 }
20882212 return 9 , nil
2213+ case ltreeKeyMarker :
2214+ return getLTreeLength (b , Ascending )
2215+ case ltreeKeyDescendingMarker :
2216+ return getLTreeLength (b , Descending )
20892217 }
20902218 if m >= IntMin && m <= IntMax {
20912219 return getVarintLen (b )
@@ -2384,6 +2512,26 @@ func prettyPrintFirstValue(dir Direction, b []byte) ([]byte, string, error) {
23842512 return b , "" , err
23852513 }
23862514 return b , d .StringNanos (), nil
2515+ case LTree :
2516+ if dir == Descending {
2517+ return b , "" , errors .Errorf ("ascending ltree column dir but descending ltree encoding" )
2518+ }
2519+ var l ltree.T
2520+ b , l , err = DecodeLTreeAscending (b )
2521+ if err != nil {
2522+ return b , "" , err
2523+ }
2524+ return b , l .String (), nil
2525+ case LTreeDesc :
2526+ if dir == Ascending {
2527+ return b , "" , errors .Errorf ("descending ltree column dir but ascending ltree encoding" )
2528+ }
2529+ var l ltree.T
2530+ b , l , err = DecodeLTreeDescending (b )
2531+ if err != nil {
2532+ return b , "" , err
2533+ }
2534+ return b , l .String (), nil
23872535 default :
23882536 if len (b ) >= 1 {
23892537 switch b [0 ] {
0 commit comments