-
Notifications
You must be signed in to change notification settings - Fork 15
/
namespace.ts
108 lines (91 loc) · 2.89 KB
/
namespace.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { Key, type Datastore, type Query, type Pair, type KeyQuery } from 'interface-datastore'
import map from 'it-map'
import { KeyTransformDatastore } from './keytransform.js'
import type { AbortOptions } from 'interface-store'
/**
* Wraps a given datastore into a keytransform which
* makes a given prefix transparent.
*
* For example, if the prefix is `new Key(/hello)` a call
* to `store.put(new Key('/world'), mydata)` would store the data under
* `/hello/world`.
*/
export class NamespaceDatastore extends KeyTransformDatastore {
private readonly iChild: Datastore
private readonly iKey: Key
constructor (child: Datastore, prefix: Key) {
super(child, {
convert (key) {
return prefix.child(key)
},
invert (key) {
if (prefix.toString() === '/') {
return key
}
if (!prefix.isAncestorOf(key)) {
throw new Error(`Expected prefix: (${prefix.toString()}) in key: ${key.toString()}`)
}
return new Key(key.toString().slice(prefix.toString().length), false)
}
})
this.iChild = child
this.iKey = prefix
}
query (q: Query, options?: AbortOptions): AsyncIterable<Pair> {
const query: Query = {
...q
}
query.filters = (query.filters ?? []).map(filter => {
return ({ key, value }) => filter({ key: this.transform.invert(key), value })
})
const { prefix } = q
if (prefix != null && prefix !== '/') {
delete query.prefix
query.filters.push(({ key }) => {
return this.transform.invert(key).toString().startsWith(prefix)
})
}
if (query.orders != null) {
query.orders = query.orders.map(order => {
return (a, b) => order(
{ key: this.transform.invert(a.key), value: a.value },
{ key: this.transform.invert(b.key), value: b.value }
)
})
}
query.filters.unshift(({ key }) => this.iKey.isAncestorOf(key))
return map(this.iChild.query(query, options), ({ key, value }) => {
return {
key: this.transform.invert(key),
value
}
})
}
queryKeys (q: KeyQuery, options?: AbortOptions): AsyncIterable<Key> {
const query = {
...q
}
query.filters = (query.filters ?? []).map(filter => {
return (key) => filter(this.transform.invert(key))
})
const { prefix } = q
if (prefix != null && prefix !== '/') {
delete query.prefix
query.filters.push((key) => {
return this.transform.invert(key).toString().startsWith(prefix)
})
}
if (query.orders != null) {
query.orders = query.orders.map(order => {
return (a, b) => order(
this.transform.invert(a),
this.transform.invert(b)
)
})
}
query.filters.unshift(key => this.iKey.isAncestorOf(key))
return map(this.iChild.queryKeys(query, options), key => {
return this.transform.invert(key)
})
}
}