@peerbit/document 7.0.13 → 7.0.14-ccaf4f4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/search.ts CHANGED
@@ -18,12 +18,14 @@ import {
18
18
  type RPCResponse,
19
19
  queryAll,
20
20
  } from "@peerbit/rpc";
21
- import { SharedLog } from "@peerbit/shared-log";
21
+ import { type ReplicationDomain, SharedLog } from "@peerbit/shared-log";
22
22
  import { SilentDelivery } from "@peerbit/stream-interface";
23
23
  import { AbortError } from "@peerbit/time";
24
24
  import { concat, fromString } from "uint8arrays";
25
25
  import { copySerialization } from "./borsh.js";
26
26
  import { MAX_BATCH_SIZE } from "./constants.js";
27
+ import { type Operation, isPutOperation } from "./operation.js";
28
+ import type { ExtractArgs } from "./program.js";
27
29
 
28
30
  const logger = loggerFn({ module: "document-index" });
29
31
 
@@ -34,119 +36,17 @@ type BufferedResult<T> = {
34
36
  from: PublicSignKey;
35
37
  };
36
38
 
37
- @variant(0)
38
- export class Operation /* <T> */ {}
39
-
40
- export const BORSH_ENCODING_OPERATION = BORSH_ENCODING(Operation);
41
-
42
- // @deprecated
43
- @variant(0)
44
- export class PutWithKeyOperation extends Operation {
45
- @field({ type: "string" })
46
- key: string;
47
-
48
- @field({ type: Uint8Array })
49
- data: Uint8Array;
50
-
51
- constructor(props: { key: string; data: Uint8Array }) {
52
- super();
53
- this.key = props.key;
54
- this.data = props.data;
55
- }
56
- }
57
-
58
- // @deprecated
59
- /* @variant(1)
60
- export class PutAllOperation<T> extends Operation<T> {
61
- @field({ type: vec(PutOperation) })
62
- docs: PutOperation<T>[];
63
-
64
- constructor(props?: { docs: PutOperation<T>[] }) {
65
- super();
66
- if (props) {
67
- this.docs = props.docs;
68
- }
69
- }
70
- }
71
- */
72
-
73
- // @deprecated
74
- @variant(2)
75
- export class DeleteByStringKeyOperation extends Operation {
76
- @field({ type: "string" })
77
- key: string;
78
-
79
- constructor(props: { key: string }) {
80
- super();
81
- this.key = props.key;
82
- }
83
-
84
- toDeleteOperation(): DeleteOperation {
85
- return new DeleteOperation({ key: indexerTypes.toId(this.key) });
86
- }
87
- }
88
-
89
- export const coerceDeleteOperation = (
90
- operation: DeleteOperation | DeleteByStringKeyOperation,
91
- ): DeleteOperation => {
92
- return operation instanceof DeleteByStringKeyOperation
93
- ? operation.toDeleteOperation()
94
- : operation;
95
- };
96
-
97
- @variant(3)
98
- export class PutOperation extends Operation {
99
- @field({ type: Uint8Array })
100
- data: Uint8Array;
101
-
102
- constructor(props: { data: Uint8Array }) {
103
- super();
104
- this.data = props.data;
105
- }
106
- }
107
-
108
- export const isPutOperation = (
109
- operation: Operation,
110
- ): operation is PutOperation | PutWithKeyOperation => {
111
- return (
112
- operation instanceof PutOperation ||
113
- operation instanceof PutWithKeyOperation
114
- );
115
- };
116
-
117
- /**
118
- * Delete a document at a key
119
- */
120
- @variant(4)
121
- export class DeleteOperation extends Operation {
122
- @field({ type: indexerTypes.IdKey })
123
- key: indexerTypes.IdKey;
124
-
125
- constructor(props: { key: indexerTypes.IdKey }) {
126
- super();
127
- this.key = props.key;
128
- }
129
- }
130
-
131
- export const isDeleteOperation = (
132
- operation: Operation,
133
- ): operation is DeleteOperation | DeleteByStringKeyOperation => {
134
- return (
135
- operation instanceof DeleteOperation ||
136
- operation instanceof DeleteByStringKeyOperation
137
- );
138
- };
139
-
140
- export type RemoteQueryOptions<R> = RPCRequestAllOptions<R> & {
141
- sync?: boolean;
39
+ export type RemoteQueryOptions<R, D> = RPCRequestAllOptions<R> & {
40
+ replicate?: boolean;
142
41
  minAge?: number;
143
42
  throwOnMissing?: boolean;
43
+ domain?: ExtractArgs<D>;
144
44
  };
145
- export type QueryOptions<R> = {
146
- remote?: boolean | RemoteQueryOptions<types.AbstractSearchResult<R>>;
45
+ export type QueryOptions<R, D> = {
46
+ remote?: boolean | RemoteQueryOptions<types.AbstractSearchResult<R>, D>;
147
47
  local?: boolean;
148
48
  };
149
- export type SearchOptions<R> = QueryOptions<R>;
49
+ export type SearchOptions<R, D> = QueryOptions<R, D>;
150
50
 
151
51
  type Transformer<T, I> = (obj: T, context: types.Context) => MaybePromise<I>;
152
52
 
@@ -156,18 +56,18 @@ export type ResultsIterator<T> = {
156
56
  done: () => boolean;
157
57
  };
158
58
 
159
- type QueryDetailedOptions<T> = QueryOptions<T> & {
59
+ type QueryDetailedOptions<T, D> = QueryOptions<T, D> & {
160
60
  onResponse?: (
161
61
  response: types.AbstractSearchResult<T>,
162
62
  from: PublicSignKey,
163
63
  ) => void | Promise<void>;
164
64
  };
165
65
 
166
- const introduceEntries = async <T>(
66
+ const introduceEntries = async <T, D>(
167
67
  responses: RPCResponse<types.AbstractSearchResult<T>>[],
168
68
  type: AbstractType<T>,
169
69
  sync: (result: types.Results<T>) => Promise<void>,
170
- options?: QueryDetailedOptions<T>,
70
+ options?: QueryDetailedOptions<T, D>,
171
71
  ): Promise<RPCResponse<types.Results<T>>[]> => {
172
72
  const results: RPCResponse<types.Results<T>>[] = [];
173
73
  for (const response of responses) {
@@ -177,7 +77,7 @@ const introduceEntries = async <T>(
177
77
 
178
78
  if (response.response instanceof types.Results) {
179
79
  response.response.results.forEach((r) => r.init(type));
180
- if (typeof options?.remote !== "boolean" && options?.remote?.sync) {
80
+ if (typeof options?.remote !== "boolean" && options?.remote?.replicate) {
181
81
  await sync(response.response);
182
82
  }
183
83
  options?.onResponse &&
@@ -290,11 +190,10 @@ const isTransformerWithFunction = <T, I>(
290
190
  return (options as TransformerAsFunction<T, I>).transform != null;
291
191
  };
292
192
 
293
- export type OpenOptions<T, I> = {
193
+ export type OpenOptions<T, I, D extends ReplicationDomain<any, Operation>> = {
294
194
  documentType: AbstractType<T>;
295
-
296
195
  dbType: AbstractType<types.IDocumentStore<T>>;
297
- log: SharedLog<Operation>;
196
+ log: SharedLog<Operation, D>;
298
197
  canRead?: CanRead<T>;
299
198
  canSearch?: CanSearch;
300
199
  sync: (result: types.Results<T>) => Promise<void>;
@@ -308,9 +207,11 @@ type IndexableClass<I> = new (
308
207
  ) => IDocumentWithContext<I>;
309
208
 
310
209
  @variant("documents_index")
311
- export class DocumentIndex<T, I extends Record<string, any>> extends Program<
312
- OpenOptions<T, I>
313
- > {
210
+ export class DocumentIndex<
211
+ T,
212
+ I extends Record<string, any>,
213
+ D extends ReplicationDomain<any, Operation>,
214
+ > extends Program<OpenOptions<T, I, D>> {
314
215
  @field({ type: RPC })
315
216
  _query: RPC<
316
217
  indexerTypes.AbstractSearchRequest,
@@ -342,7 +243,7 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
342
243
 
343
244
  private _sync: (result: types.Results<T>) => Promise<void>;
344
245
 
345
- private _log: SharedLog<Operation>;
246
+ private _log: SharedLog<Operation, D>;
346
247
 
347
248
  private _resolverProgramCache?: Map<string | number | bigint, T>;
348
249
  private _resolverCache: Cache<T>;
@@ -372,7 +273,7 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
372
273
  return this._valueEncoding;
373
274
  }
374
275
 
375
- async open(properties: OpenOptions<T, I>) {
276
+ async open(properties: OpenOptions<T, I, D>) {
376
277
  this._log = properties.log;
377
278
 
378
279
  this.documentType = properties.documentType;
@@ -527,7 +428,7 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
527
428
 
528
429
  public async get(
529
430
  key: indexerTypes.Ideable | indexerTypes.IdKey,
530
- options?: QueryOptions<T>,
431
+ options?: QueryOptions<T, D>,
531
432
  ): Promise<T | undefined> {
532
433
  return (
533
434
  await this.getDetailed(
@@ -579,7 +480,7 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
579
480
 
580
481
  public async getDetailed(
581
482
  key: indexerTypes.IdKey | indexerTypes.IdPrimitive,
582
- options?: QueryOptions<T>,
483
+ options?: QueryOptions<T, D>,
583
484
  ): Promise<types.Results<T>[] | undefined> {
584
485
  let results: types.Results<T>[] | undefined;
585
486
  if (key instanceof Uint8Array) {
@@ -808,11 +709,12 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
808
709
  */
809
710
  public async queryDetailed(
810
711
  queryRequest: indexerTypes.SearchRequest,
811
- options?: QueryDetailedOptions<T>,
712
+ options?: QueryDetailedOptions<T, D>,
812
713
  ): Promise<types.Results<T>[]> {
813
714
  const local = typeof options?.local === "boolean" ? options?.local : true;
814
- let remote: RemoteQueryOptions<types.AbstractSearchResult<T>> | undefined =
815
- undefined;
715
+ let remote:
716
+ | RemoteQueryOptions<types.AbstractSearchResult<T>, D>
717
+ | undefined = undefined;
816
718
  if (typeof options?.remote === "boolean") {
817
719
  if (options?.remote) {
818
720
  remote = {};
@@ -829,7 +731,6 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
829
731
  remote.priority = 1;
830
732
  }
831
733
 
832
- const promises: Promise<types.Results<T>[] | undefined>[] = [];
833
734
  if (!local && !remote) {
834
735
  throw new Error(
835
736
  "Expecting either 'options.remote' or 'options.local' to be true",
@@ -850,53 +751,50 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
850
751
  }
851
752
  }
852
753
 
754
+ let resolved: types.Results<T>[] = [];
853
755
  if (remote) {
854
- const replicatorGroups = await this._log.getReplicatorUnion(
756
+ const replicatorGroups = await this._log.getCover(
757
+ remote.domain ?? (undefined as any),
855
758
  remote.minAge,
856
759
  );
857
760
 
858
761
  if (replicatorGroups) {
859
762
  const groupHashes: string[][] = replicatorGroups.map((x) => [x]);
860
- const fn = async () => {
861
- const rs: types.Results<T>[] = [];
862
- const responseHandler = async (
863
- results: RPCResponse<types.AbstractSearchResult<T>>[],
864
- ) => {
865
- for (const r of await introduceEntries(
866
- results,
867
- this.documentType,
868
- this._sync,
869
- options,
870
- )) {
871
- rs.push(r.response);
872
- }
873
- };
874
- try {
875
- if (queryRequest instanceof indexerTypes.CloseIteratorRequest) {
876
- // don't wait for responses
877
- await this._query.request(queryRequest, { mode: remote!.mode });
878
- } else {
879
- await queryAll(
880
- this._query,
881
- groupHashes,
882
- queryRequest,
883
- responseHandler,
884
- remote,
885
- );
886
- }
887
- } catch (error) {
888
- if (error instanceof MissingResponsesError) {
889
- logger.warn("Did not reciveve responses from all shard");
890
- if (remote?.throwOnMissing) {
891
- throw error;
892
- }
893
- } else {
763
+ const responseHandler = async (
764
+ results: RPCResponse<types.AbstractSearchResult<T>>[],
765
+ ) => {
766
+ for (const r of await introduceEntries(
767
+ results,
768
+ this.documentType,
769
+ this._sync,
770
+ options,
771
+ )) {
772
+ resolved.push(r.response);
773
+ }
774
+ };
775
+ try {
776
+ if (queryRequest instanceof indexerTypes.CloseIteratorRequest) {
777
+ // don't wait for responses
778
+ await this._query.request(queryRequest, { mode: remote!.mode });
779
+ } else {
780
+ await queryAll(
781
+ this._query,
782
+ groupHashes,
783
+ queryRequest,
784
+ responseHandler,
785
+ remote,
786
+ );
787
+ }
788
+ } catch (error) {
789
+ if (error instanceof MissingResponsesError) {
790
+ logger.warn("Did not reciveve responses from all shard");
791
+ if (remote?.throwOnMissing) {
894
792
  throw error;
895
793
  }
794
+ } else {
795
+ throw error;
896
796
  }
897
- return rs;
898
- };
899
- promises.push(fn());
797
+ }
900
798
  } else {
901
799
  // TODO send without direction out to the world? or just assume we can insert?
902
800
  /* promises.push(
@@ -909,7 +807,6 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
909
807
  ); */
910
808
  }
911
809
  }
912
- const resolved = await Promise.all(promises);
913
810
  for (const r of resolved) {
914
811
  if (r) {
915
812
  if (r instanceof Array) {
@@ -930,7 +827,7 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
930
827
  */
931
828
  public async search(
932
829
  queryRequest: indexerTypes.SearchRequest,
933
- options?: SearchOptions<T>,
830
+ options?: SearchOptions<T, D>,
934
831
  ): Promise<T[]> {
935
832
  // Set fetch to search size, or max value (default to max u32 (4294967295))
936
833
  queryRequest.fetch = queryRequest.fetch ?? 0xffffffff;
@@ -966,7 +863,7 @@ export class DocumentIndex<T, I extends Record<string, any>> extends Program<
966
863
  */
967
864
  public iterate(
968
865
  queryRequest: indexerTypes.SearchRequest,
969
- options?: QueryOptions<T>,
866
+ options?: QueryOptions<T, D>,
970
867
  ): ResultsIterator<T> {
971
868
  let fetchPromise: Promise<any> | undefined = undefined;
972
869
  const peerBufferMap: Map<