55
66import { Transformer , prefixTransformer , defaultTransformer , defaultGetRange } from "./transformer"
77import { NativeValue } from "./native"
8- import { asBuf , concat2 , startsWith } from "./util"
8+ import {
9+ asBuf , concat2 , startsWith , strInc
10+ } from "./util"
11+ import { UnboundStamp } from './versionstamp.js'
912
1013const EMPTY_BUF = Buffer . alloc ( 0 )
1114
@@ -26,7 +29,14 @@ export default class Subspace<KeyIn = NativeValue, KeyOut = Buffer, ValIn = Nati
2629
2730 _bakedKeyXf : Transformer < KeyIn , KeyOut > // This is cached from _prefix + keyXf.
2831
29- constructor ( rawPrefix : string | Buffer | null , keyXf ?: Transformer < KeyIn , KeyOut > , valueXf ?: Transformer < ValIn , ValOut > ) {
32+ _noDefaultPrefix : boolean
33+
34+ constructor (
35+ rawPrefix : string | Buffer | null ,
36+ keyXf ?: Transformer < KeyIn , KeyOut > ,
37+ valueXf ?: Transformer < ValIn , ValOut > ,
38+ noDefaultPrefix : boolean = false
39+ ) {
3040 this . prefix = rawPrefix != null ? Buffer . from ( rawPrefix ) : EMPTY_BUF
3141
3242 // Ugh typing this is a mess. Usually this will be fine since if you say new
@@ -35,6 +45,24 @@ export default class Subspace<KeyIn = NativeValue, KeyOut = Buffer, ValIn = Nati
3545 this . valueXf = valueXf || ( defaultTransformer as Transformer < any , any > )
3646
3747 this . _bakedKeyXf = rawPrefix ? prefixTransformer ( rawPrefix , this . keyXf ) : this . keyXf
48+
49+ this . _noDefaultPrefix = noDefaultPrefix
50+ }
51+
52+ /**
53+ * Switch to a new mode of handling ranges. By default, the range operations (`getRange` family
54+ * and `clearRange`) treat calls with missing end key as operations on prefix ranges. That means
55+ * that a call like `tn.at('a').getRange('x')` acts on prefix `ax`, ie key range `[ax, ay)`. In
56+ * the new mode, the missing end key defaults to a subspace end (inclusive), ie that call would
57+ * act on a range `[ax, b)`. This enabled specifying key ranges not possible before.
58+ *
59+ * To specifiy range as a prefix, use `StartsWith` version of those methods (eg
60+ * `getRangeAllStartsWith`).
61+ *
62+ * @see Subspace.packRange
63+ */
64+ noDefaultPrefix ( ) {
65+ return new Subspace ( this . prefix , this . keyXf , this . valueXf , true )
3866 }
3967
4068 // All these template parameters make me question my life choices, but this is
@@ -48,21 +76,21 @@ export default class Subspace<KeyIn = NativeValue, KeyOut = Buffer, ValIn = Nati
4876 // ***
4977 at ( prefix : KeyIn | null , keyXf : Transformer < any , any > = this . keyXf , valueXf : Transformer < any , any > = this . valueXf ) {
5078 const _prefix = prefix == null ? null : this . keyXf . pack ( prefix )
51- return new Subspace ( concatPrefix ( this . prefix , _prefix ) , keyXf , valueXf )
79+ return new Subspace ( concatPrefix ( this . prefix , _prefix ) , keyXf , valueXf , this . _noDefaultPrefix )
5280 }
5381
5482 /** At a child prefix thats specified without reference to the key transformer */
5583 atRaw ( prefix : Buffer ) {
56- return new Subspace ( concatPrefix ( this . prefix , prefix ) , this . keyXf , this . valueXf )
84+ return new Subspace ( concatPrefix ( this . prefix , prefix ) , this . keyXf , this . valueXf , this . _noDefaultPrefix )
5785 }
5886
5987
6088 withKeyEncoding < CKI , CKO > ( keyXf : Transformer < CKI , CKO > ) : Subspace < CKI , CKO , ValIn , ValOut > {
61- return new Subspace ( this . prefix , keyXf , this . valueXf )
89+ return new Subspace ( this . prefix , keyXf , this . valueXf , this . _noDefaultPrefix )
6290 }
6391
6492 withValueEncoding < CVI , CVO > ( valXf : Transformer < CVI , CVO > ) : Subspace < KeyIn , KeyOut , CVI , CVO > {
65- return new Subspace ( this . prefix , this . keyXf , valXf )
93+ return new Subspace ( this . prefix , this . keyXf , valXf , this . _noDefaultPrefix )
6694 }
6795
6896 // GetSubspace implementation
@@ -75,17 +103,62 @@ export default class Subspace<KeyIn = NativeValue, KeyOut = Buffer, ValIn = Nati
75103 unpackKey ( key : Buffer ) : KeyOut {
76104 return this . _bakedKeyXf . unpack ( key )
77105 }
106+ packKeyUnboundVersionstamp ( key : KeyIn ) : UnboundStamp {
107+ if ( ! this . keyXf . packUnboundVersionstamp ) {
108+ throw TypeError ( 'Value encoding does not support unbound versionstamps. Use setVersionstampPrefixedValue instead' )
109+ }
110+
111+ return this . keyXf . packUnboundVersionstamp ( key )
112+ }
78113 packValue ( val : ValIn ) : NativeValue {
79114 return this . valueXf . pack ( val )
80115 }
81116 unpackValue ( val : Buffer ) : ValOut {
82117 return this . valueXf . unpack ( val )
83118 }
119+ packValueUnboundVersionstamp ( value : ValIn ) : UnboundStamp {
120+ if ( ! this . valueXf . packUnboundVersionstamp ) {
121+ throw TypeError ( 'Value encoding does not support unbound versionstamps. Use setVersionstampPrefixedValue instead' )
122+ }
123+
124+ return this . valueXf . packUnboundVersionstamp ( value )
125+ }
126+
127+ /**
128+ * Encodes a range specified by `start`/`end` pair using configured key encoder.
129+ *
130+ * @param start Start of the key range. If undefined, the start of the subspace is assumed.
131+ * @param end Start of the key range. If undefined, the end of the subspace is assumed, unless
132+ * `noDefaultPrefix` flag is set or enabled for this subspace, in which case, start key is treated
133+ * as a prefix.
134+ * @param noDefaultPrefix Disable treating start key as a prefix if end key is not specified.
135+ * @returns Encoded range as a `{ begin, end }` record.
136+ */
137+ packRange (
138+ start ?: KeyIn ,
139+ end ?: KeyIn ,
140+ noDefaultPrefix : boolean = false
141+ ) : { begin : NativeValue , end : NativeValue } {
142+ if ( start !== undefined && end === undefined && ! this . _noDefaultPrefix && ! noDefaultPrefix ) {
143+ return this . packRangeStartsWith ( start )
144+ }
145+
146+ return {
147+ begin : start !== undefined ? this . _bakedKeyXf . pack ( start ) : this . prefix ,
148+ end : end !== undefined ? this . _bakedKeyXf . pack ( end ) : strInc ( this . prefix )
149+ }
150+ }
151+
152+ /**
153+ * Encodes a range specified by the prefix using configured key encoder.
154+ *
155+ * @param start Start of the key key range. If undefined, the start of the subspace is assumed.
156+ * @returns Encoded range as a `{ begin, end }` record.
157+ */
158+ packRangeStartsWith ( prefix : KeyIn ) : { begin : NativeValue , end : NativeValue } {
159+ const encodePrefix = this . _bakedKeyXf . range ?? defaultGetRange
84160
85- packRange ( prefix : KeyIn ) : { begin : NativeValue , end : NativeValue } {
86- // if (this._bakedKeyXf.range) return this._bakedKeyXf.range(prefix)
87- // else return defaultGetRange(prefix, this._bakedKeyXf)
88- return ( this . _bakedKeyXf . range || defaultGetRange ) ( prefix , this . _bakedKeyXf )
161+ return encodePrefix ( prefix , this . _bakedKeyXf )
89162 }
90163
91164 contains ( key : NativeValue ) {
0 commit comments