@dxos/app-graph 0.8.4-main.b97322e → 0.8.4-main.bc674ce
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/dist/lib/browser/index.mjs +1131 -612
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +1130 -612
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/atoms.d.ts +8 -0
- package/dist/types/src/atoms.d.ts.map +1 -0
- package/dist/types/src/graph-builder.d.ts +113 -60
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +183 -209
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +6 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/node-matcher.d.ts +218 -0
- package/dist/types/src/node-matcher.d.ts.map +1 -0
- package/dist/types/src/node-matcher.test.d.ts +2 -0
- package/dist/types/src/node-matcher.test.d.ts.map +1 -0
- package/dist/types/src/node.d.ts +32 -3
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts +8 -10
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +37 -35
- package/src/atoms.ts +25 -0
- package/src/graph-builder.test.ts +571 -97
- package/src/graph-builder.ts +600 -258
- package/src/graph.test.ts +300 -107
- package/src/graph.ts +971 -400
- package/src/index.ts +9 -3
- package/src/node-matcher.test.ts +301 -0
- package/src/node-matcher.ts +284 -0
- package/src/node.ts +39 -6
- package/src/stories/EchoGraph.stories.tsx +119 -108
- package/src/stories/Tree.tsx +2 -2
- package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
- package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
- package/dist/types/src/signals-integration.test.d.ts +0 -2
- package/dist/types/src/signals-integration.test.d.ts.map +0 -1
- package/dist/types/src/testing.d.ts +0 -5
- package/dist/types/src/testing.d.ts.map +0 -1
- package/src/experimental/graph-projections.test.ts +0 -56
- package/src/signals-integration.test.ts +0 -218
- package/src/testing.ts +0 -20
|
@@ -2,39 +2,31 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Query,
|
|
16
|
-
type QueryResult,
|
|
17
|
-
type Space,
|
|
18
|
-
SpaceState,
|
|
19
|
-
Expando,
|
|
20
|
-
type Live,
|
|
21
|
-
Filter,
|
|
22
|
-
} from '@dxos/client/echo';
|
|
23
|
-
import { Obj, Type } from '@dxos/echo';
|
|
5
|
+
import { Atom, type Registry, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
|
|
6
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
|
+
import * as Function from 'effect/Function';
|
|
8
|
+
import * as Option from 'effect/Option';
|
|
9
|
+
import React, { type PropsWithChildren, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
10
|
+
|
|
11
|
+
import { Filter, type Space, SpaceState, isSpace } from '@dxos/client/echo';
|
|
12
|
+
import { Obj, Query } from '@dxos/echo';
|
|
13
|
+
import { TestSchema } from '@dxos/echo/testing';
|
|
14
|
+
import { AtomObj, AtomQuery } from '@dxos/echo-atom';
|
|
24
15
|
import { faker } from '@dxos/random';
|
|
25
16
|
import { type Client, useClient } from '@dxos/react-client';
|
|
26
17
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
27
|
-
import {
|
|
18
|
+
import { Icon, IconButton, Input, Select } from '@dxos/react-ui';
|
|
19
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
28
20
|
import { Path, Tree } from '@dxos/react-ui-list';
|
|
29
|
-
import { getSize, mx } from '@dxos/
|
|
30
|
-
import { withTheme } from '@dxos/storybook-utils';
|
|
21
|
+
import { getSize, mx } from '@dxos/ui-theme';
|
|
31
22
|
import { byPosition, isNonNullable, safeParseInt } from '@dxos/util';
|
|
32
23
|
|
|
24
|
+
import * as CreateAtom from '../atoms';
|
|
25
|
+
import * as Graph from '../graph';
|
|
26
|
+
import * as GraphBuilder from '../graph-builder';
|
|
27
|
+
import * as Node from '../node';
|
|
28
|
+
|
|
33
29
|
import { JsonTree } from './Tree';
|
|
34
|
-
import { type ExpandableGraph, ROOT_ID } from '../graph';
|
|
35
|
-
import { GraphBuilder, createExtension, rxFromObservable, rxFromSignal } from '../graph-builder';
|
|
36
|
-
import { type Node } from '../node';
|
|
37
|
-
import { rxFromQuery } from '../testing';
|
|
38
30
|
|
|
39
31
|
const DEFAULT_PERIOD = 500;
|
|
40
32
|
|
|
@@ -56,43 +48,44 @@ const actionWeights = {
|
|
|
56
48
|
[Action.RENAME_OBJECT]: 4,
|
|
57
49
|
};
|
|
58
50
|
|
|
59
|
-
const createGraph = (client: Client, registry: Registry.Registry): ExpandableGraph => {
|
|
60
|
-
const spaceBuilderExtension =
|
|
51
|
+
const createGraph = (client: Client, registry: Registry.Registry): Graph.ExpandableGraph => {
|
|
52
|
+
const spaceBuilderExtension = GraphBuilder.createExtensionRaw({
|
|
61
53
|
id: 'space',
|
|
62
54
|
connector: (node) =>
|
|
63
|
-
|
|
64
|
-
pipe(
|
|
55
|
+
Atom.make((get) =>
|
|
56
|
+
Function.pipe(
|
|
65
57
|
get(node),
|
|
66
|
-
Option.flatMap((node) => (node.id ===
|
|
58
|
+
Option.flatMap((node) => (node.id === Node.RootId ? Option.some(node) : Option.none())),
|
|
67
59
|
Option.map(() => {
|
|
68
|
-
const spaces = get(
|
|
60
|
+
const spaces = get(CreateAtom.fromObservable(client.spaces)) ?? [];
|
|
69
61
|
return spaces
|
|
70
|
-
.filter((space) => get(
|
|
71
|
-
.map((space) =>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
62
|
+
.filter((space: any) => get(CreateAtom.fromObservable(space.state)) === SpaceState.SPACE_READY)
|
|
63
|
+
.map((space) => {
|
|
64
|
+
const propertiesSnapshot = get(AtomObj.make(space.properties));
|
|
65
|
+
return {
|
|
66
|
+
id: space.id,
|
|
67
|
+
type: 'dxos.org/type/Space',
|
|
68
|
+
properties: {
|
|
69
|
+
label: propertiesSnapshot.name,
|
|
70
|
+
},
|
|
71
|
+
data: space,
|
|
72
|
+
};
|
|
73
|
+
});
|
|
77
74
|
}),
|
|
78
75
|
Option.getOrElse(() => []),
|
|
79
76
|
),
|
|
80
77
|
),
|
|
81
78
|
});
|
|
82
79
|
|
|
83
|
-
const objectBuilderExtension =
|
|
80
|
+
const objectBuilderExtension = GraphBuilder.createExtensionRaw({
|
|
84
81
|
id: 'object',
|
|
85
82
|
connector: (node) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
pipe(
|
|
83
|
+
return Atom.make((get) =>
|
|
84
|
+
Function.pipe(
|
|
89
85
|
get(node),
|
|
90
86
|
Option.flatMap((node) => (isSpace(node.data) ? Option.some(node.data) : Option.none())),
|
|
91
87
|
Option.map((space) => {
|
|
92
|
-
|
|
93
|
-
query = space.db.query(Query.type(Expando, { type: 'test' }));
|
|
94
|
-
}
|
|
95
|
-
const objects = get(rxFromQuery(query));
|
|
88
|
+
const objects = get(AtomQuery.make(space.db, Query.type(TestSchema.Expando, { type: 'test' })));
|
|
96
89
|
return objects.map((object) => ({
|
|
97
90
|
id: object.id,
|
|
98
91
|
type: 'dxos.org/type/test',
|
|
@@ -106,15 +99,15 @@ const createGraph = (client: Client, registry: Registry.Registry): ExpandableGra
|
|
|
106
99
|
},
|
|
107
100
|
});
|
|
108
101
|
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
const builder = GraphBuilder.make({ registry });
|
|
103
|
+
GraphBuilder.addExtension(builder, spaceBuilderExtension);
|
|
104
|
+
GraphBuilder.addExtension(builder, objectBuilderExtension);
|
|
105
|
+
const graph = builder.graph;
|
|
112
106
|
graph.onNodeChanged.on(({ id }) => {
|
|
113
|
-
|
|
107
|
+
Graph.expand(graph, id);
|
|
114
108
|
});
|
|
115
|
-
|
|
109
|
+
Graph.expand(graph, Node.RootId);
|
|
116
110
|
(window as any).graph = graph;
|
|
117
|
-
|
|
118
111
|
return graph;
|
|
119
112
|
};
|
|
120
113
|
|
|
@@ -134,9 +127,9 @@ const getRandomSpace = (client: Client): Space | undefined => {
|
|
|
134
127
|
const getSpaceWithObjects = async (client: Client): Promise<Space | undefined> => {
|
|
135
128
|
const readySpaces = client.spaces.get().filter((space) => space.state.get() === SpaceState.SPACE_READY);
|
|
136
129
|
const spaceQueries = await Promise.all(
|
|
137
|
-
readySpaces.map((space) => space.db.query(Filter.type(Expando, { type: 'test' })).run()),
|
|
130
|
+
readySpaces.map((space) => space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run()),
|
|
138
131
|
);
|
|
139
|
-
const spaces = readySpaces.filter((space, index) => spaceQueries[index].
|
|
132
|
+
const spaces = readySpaces.filter((space, index) => spaceQueries[index].length > 0);
|
|
140
133
|
return spaces[Math.floor(Math.random() * spaces.length)];
|
|
141
134
|
};
|
|
142
135
|
|
|
@@ -153,19 +146,26 @@ const runAction = async (client: Client, action: Action) => {
|
|
|
153
146
|
case Action.RENAME_SPACE: {
|
|
154
147
|
const space = getRandomSpace(client);
|
|
155
148
|
if (space) {
|
|
156
|
-
space.properties
|
|
149
|
+
Obj.change(space.properties, (p) => {
|
|
150
|
+
p.name = faker.commerce.productName();
|
|
151
|
+
});
|
|
157
152
|
}
|
|
158
153
|
break;
|
|
159
154
|
}
|
|
160
155
|
|
|
161
156
|
case Action.ADD_OBJECT:
|
|
162
|
-
getRandomSpace(client)?.db.add(
|
|
157
|
+
getRandomSpace(client)?.db.add(
|
|
158
|
+
Obj.make(TestSchema.Expando, {
|
|
159
|
+
type: 'test',
|
|
160
|
+
name: faker.commerce.productName(),
|
|
161
|
+
}),
|
|
162
|
+
);
|
|
163
163
|
break;
|
|
164
164
|
|
|
165
165
|
case Action.REMOVE_OBJECT: {
|
|
166
166
|
const space = await getSpaceWithObjects(client);
|
|
167
167
|
if (space) {
|
|
168
|
-
const
|
|
168
|
+
const objects = await space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run();
|
|
169
169
|
space.db.remove(objects[Math.floor(Math.random() * objects.length)]);
|
|
170
170
|
}
|
|
171
171
|
break;
|
|
@@ -174,8 +174,11 @@ const runAction = async (client: Client, action: Action) => {
|
|
|
174
174
|
case Action.RENAME_OBJECT: {
|
|
175
175
|
const space = await getSpaceWithObjects(client);
|
|
176
176
|
if (space) {
|
|
177
|
-
const
|
|
178
|
-
objects[Math.floor(Math.random() * objects.length)]
|
|
177
|
+
const objects = await space.db.query(Filter.type(TestSchema.Expando, { type: 'test' })).run();
|
|
178
|
+
const object = objects[Math.floor(Math.random() * objects.length)];
|
|
179
|
+
Obj.change(object, (o) => {
|
|
180
|
+
o.name = faker.commerce.productName();
|
|
181
|
+
});
|
|
179
182
|
}
|
|
180
183
|
break;
|
|
181
184
|
}
|
|
@@ -214,7 +217,7 @@ const Controls = ({ children }: PropsWithChildren) => {
|
|
|
214
217
|
<Input.TextInput
|
|
215
218
|
autoComplete='off'
|
|
216
219
|
size={5}
|
|
217
|
-
classNames='
|
|
220
|
+
classNames='is-[100px] text-right pie-[22px]'
|
|
218
221
|
placeholder='Interval'
|
|
219
222
|
value={actionInterval}
|
|
220
223
|
onChange={({ target: { value } }) => setActionInterval(value)}
|
|
@@ -246,28 +249,30 @@ const Controls = ({ children }: PropsWithChildren) => {
|
|
|
246
249
|
);
|
|
247
250
|
};
|
|
248
251
|
|
|
249
|
-
const meta
|
|
252
|
+
const meta = {
|
|
250
253
|
title: 'sdk/app-graph/EchoGraph',
|
|
251
254
|
decorators: [
|
|
255
|
+
withTheme,
|
|
252
256
|
withClientProvider({
|
|
253
257
|
createIdentity: true,
|
|
254
|
-
|
|
258
|
+
onCreateIdentity: async ({ client }) => {
|
|
255
259
|
await client.spaces.create();
|
|
256
260
|
await client.spaces.create();
|
|
257
261
|
},
|
|
258
262
|
}),
|
|
259
|
-
withTheme,
|
|
260
263
|
],
|
|
261
|
-
};
|
|
264
|
+
} satisfies Meta;
|
|
262
265
|
|
|
263
266
|
export default meta;
|
|
264
267
|
|
|
265
|
-
|
|
268
|
+
type Story = StoryObj<typeof meta>;
|
|
269
|
+
|
|
270
|
+
export const JsonView: Story = {
|
|
266
271
|
render: () => {
|
|
267
272
|
const client = useClient();
|
|
268
273
|
const registry = useContext(RegistryContext);
|
|
269
274
|
const graph = useMemo(() => createGraph(client, registry), [client, registry]);
|
|
270
|
-
const data =
|
|
275
|
+
const data = useAtomValue(graph.json());
|
|
271
276
|
|
|
272
277
|
return (
|
|
273
278
|
<>
|
|
@@ -278,31 +283,42 @@ export const JsonView = {
|
|
|
278
283
|
},
|
|
279
284
|
};
|
|
280
285
|
|
|
281
|
-
export const TreeView = {
|
|
286
|
+
export const TreeView: Story = {
|
|
282
287
|
render: () => {
|
|
283
288
|
const client = useClient();
|
|
284
289
|
const registry = useContext(RegistryContext);
|
|
285
290
|
const graph = useMemo(() => createGraph(client, registry), [client, registry]);
|
|
286
|
-
const
|
|
291
|
+
const stateRef = useRef(new Map<string, Atom.Writable<{ open: boolean; current: boolean }>>());
|
|
292
|
+
|
|
293
|
+
const getOrCreateState = useMemo(
|
|
294
|
+
() => (path: string) => {
|
|
295
|
+
let atom = stateRef.current.get(path);
|
|
296
|
+
if (!atom) {
|
|
297
|
+
atom = Atom.make({ open: true, current: false }).pipe(Atom.keepAlive);
|
|
298
|
+
stateRef.current.set(path, atom);
|
|
299
|
+
}
|
|
300
|
+
return atom;
|
|
301
|
+
},
|
|
302
|
+
[],
|
|
303
|
+
);
|
|
287
304
|
|
|
288
305
|
const useItems = useCallback(
|
|
289
|
-
(node?: Node, options?: { disposition?: string; sort?: boolean }) => {
|
|
290
|
-
const connections =
|
|
306
|
+
(node?: Node.Node, options?: { disposition?: string; sort?: boolean }) => {
|
|
307
|
+
const connections = useAtomValue(graph.connections(node?.id ?? Node.RootId));
|
|
291
308
|
return options?.sort ? connections.toSorted((a, b) => byPosition(a.properties, b.properties)) : connections;
|
|
292
309
|
},
|
|
293
310
|
[graph],
|
|
294
311
|
);
|
|
295
312
|
|
|
296
313
|
const getProps = useCallback(
|
|
297
|
-
(node: Node, path: string[]) => {
|
|
298
|
-
const children = graph
|
|
299
|
-
.getConnections(node.id, 'outbound')
|
|
314
|
+
(node: Node.Node, path: string[]) => {
|
|
315
|
+
const children = Graph.getConnections(graph, node.id, 'outbound')
|
|
300
316
|
.map((n) => {
|
|
301
317
|
// Break cycles.
|
|
302
318
|
const nextPath = [...path, node.id];
|
|
303
|
-
return nextPath.includes(n.id) ? undefined : (n as Node);
|
|
319
|
+
return nextPath.includes(n.id) ? undefined : (n as Node.Node);
|
|
304
320
|
})
|
|
305
|
-
.filter(isNonNullable) as Node[];
|
|
321
|
+
.filter(isNonNullable) as Node.Node[];
|
|
306
322
|
const parentOf =
|
|
307
323
|
children.length > 0 ? children.map(({ id }) => id) : node.properties.role === 'branch' ? [] : undefined;
|
|
308
324
|
return {
|
|
@@ -315,59 +331,54 @@ export const TreeView = {
|
|
|
315
331
|
[graph],
|
|
316
332
|
);
|
|
317
333
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
334
|
+
// Hook that subscribes to item state via Atom.
|
|
335
|
+
const useItemState = (_path: string[]) => {
|
|
336
|
+
const path = useMemo(() => Path.create(..._path), [_path.join('~')]);
|
|
337
|
+
const atom = getOrCreateState(path);
|
|
338
|
+
return useAtomValue(atom);
|
|
339
|
+
};
|
|
325
340
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
);
|
|
330
|
-
|
|
331
|
-
const isCurrent = useCallback(
|
|
332
|
-
(_path: string[]) => {
|
|
333
|
-
const path = Path.create(..._path);
|
|
334
|
-
const object = state.get(path) ?? live({ open: false, current: false });
|
|
335
|
-
if (!state.has(path)) {
|
|
336
|
-
state.set(path, object);
|
|
337
|
-
}
|
|
341
|
+
const useIsOpen = (_path: string[]) => {
|
|
342
|
+
return useItemState(_path).open;
|
|
343
|
+
};
|
|
338
344
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
);
|
|
345
|
+
const useIsCurrent = (_path: string[]) => {
|
|
346
|
+
return useItemState(_path).current;
|
|
347
|
+
};
|
|
343
348
|
|
|
344
349
|
const onOpenChange = useCallback(
|
|
345
350
|
({ path: _path, open }: { path: string[]; open: boolean }) => {
|
|
346
351
|
const path = Path.create(..._path);
|
|
347
|
-
const
|
|
348
|
-
|
|
352
|
+
const atom = stateRef.current.get(path);
|
|
353
|
+
if (atom) {
|
|
354
|
+
const prev = registry.get(atom);
|
|
355
|
+
registry.set(atom, { ...prev, open });
|
|
356
|
+
}
|
|
349
357
|
},
|
|
350
|
-
[
|
|
358
|
+
[registry],
|
|
351
359
|
);
|
|
352
360
|
|
|
353
361
|
const onSelect = useCallback(
|
|
354
362
|
({ path: _path, current }: { path: string[]; current: boolean }) => {
|
|
355
363
|
const path = Path.create(..._path);
|
|
356
|
-
const
|
|
357
|
-
|
|
364
|
+
const atom = stateRef.current.get(path);
|
|
365
|
+
if (atom) {
|
|
366
|
+
const prev = registry.get(atom);
|
|
367
|
+
registry.set(atom, { ...prev, current });
|
|
368
|
+
}
|
|
358
369
|
},
|
|
359
|
-
[
|
|
370
|
+
[registry],
|
|
360
371
|
);
|
|
361
372
|
|
|
362
373
|
return (
|
|
363
374
|
<>
|
|
364
375
|
<Controls />
|
|
365
376
|
<Tree
|
|
366
|
-
id={
|
|
377
|
+
id={Node.RootId}
|
|
367
378
|
useItems={useItems}
|
|
368
379
|
getProps={getProps}
|
|
369
|
-
|
|
370
|
-
|
|
380
|
+
useIsOpen={useIsOpen}
|
|
381
|
+
useIsCurrent={useIsCurrent}
|
|
371
382
|
onOpenChange={onOpenChange}
|
|
372
383
|
onSelect={onSelect}
|
|
373
384
|
/>
|
package/src/stories/Tree.tsx
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { type FC, type HTMLAttributes, useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import { mx } from '@dxos/
|
|
7
|
+
import { mx } from '@dxos/ui-theme';
|
|
8
8
|
|
|
9
9
|
// TODO(burdon): Copied form devtools.
|
|
10
10
|
|
|
@@ -72,7 +72,7 @@ const Scalar: FC<{ value: any }> = ({ value }) => {
|
|
|
72
72
|
|
|
73
73
|
const Box: FC<HTMLAttributes<HTMLDivElement>> = ({ children, className, ...props }) => {
|
|
74
74
|
return (
|
|
75
|
-
<div className={mx('flex
|
|
75
|
+
<div className={mx('flex pli-2 border border-l-0 font-mono truncate', className)} {...props}>
|
|
76
76
|
{children}
|
|
77
77
|
</div>
|
|
78
78
|
);
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
type Cb = () => void;
|
|
2
|
-
interface Query {
|
|
3
|
-
id?: string[];
|
|
4
|
-
typename?: string[];
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Lazy query result that can be executed.
|
|
8
|
-
* Does not run without the run function being called.
|
|
9
|
-
*/
|
|
10
|
-
interface QueryResult<T> {
|
|
11
|
-
/**
|
|
12
|
-
* Execute the query and subscribe to the result.
|
|
13
|
-
* @param next Called at least once with the first value (maybe synchronously) and then for every subsequent update.
|
|
14
|
-
* @param error Called on error. `next` is never called after that.
|
|
15
|
-
* @returns Function to dispose the query and unsubscribe.
|
|
16
|
-
*/
|
|
17
|
-
run(onData: (value?: T[]) => void, onError: (err: Error) => void): Cb;
|
|
18
|
-
}
|
|
19
|
-
declare const QueryResult: Readonly<{
|
|
20
|
-
fromPromise: <T>(run: (onDispose: (cb: Cb) => void) => Promise<T[]>) => QueryResult<T>;
|
|
21
|
-
}>;
|
|
22
|
-
interface _Resolver<T> {
|
|
23
|
-
query(query: Query): QueryResult<T>;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=graph-projections.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"graph-projections.test.d.ts","sourceRoot":"","sources":["../../../../src/experimental/graph-projections.test.ts"],"names":[],"mappings":"AAIA,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC;AAErB,UAAU,KAAK;IACb,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;GAGG;AACH,UAAU,WAAW,CAAC,CAAC;IACrB;;;;;OAKG;IACH,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,GAAG,EAAE,CAAC;CACvE;AAED,QAAA,MAAM,WAAW;kBACD,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,IAAI,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,KAAG,WAAW,CAAC,CAAC,CAAC;EAyBpF,CAAC;AAEH,UAAU,SAAS,CAAC,CAAC;IACnB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;CACrC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signals-integration.test.d.ts","sourceRoot":"","sources":["../../../src/signals-integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { Rx } from '@effect-rx/rx-react';
|
|
2
|
-
import { type QueryResult } from '@dxos/echo-db';
|
|
3
|
-
import { type AnyEchoObject } from '@dxos/echo-schema';
|
|
4
|
-
export declare const rxFromQuery: <T extends AnyEchoObject>(query: QueryResult<T>) => Rx.Rx<T[]>;
|
|
5
|
-
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../src/testing.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAEzC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,aAAa,EAAE,OAAO,WAAW,CAAC,CAAC,CAAC,KAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAUrF,CAAC"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
type Cb = () => void;
|
|
6
|
-
|
|
7
|
-
interface Query {
|
|
8
|
-
id?: string[];
|
|
9
|
-
typename?: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Lazy query result that can be executed.
|
|
14
|
-
* Does not run without the run function being called.
|
|
15
|
-
*/
|
|
16
|
-
interface QueryResult<T> {
|
|
17
|
-
/**
|
|
18
|
-
* Execute the query and subscribe to the result.
|
|
19
|
-
* @param next Called at least once with the first value (maybe synchronously) and then for every subsequent update.
|
|
20
|
-
* @param error Called on error. `next` is never called after that.
|
|
21
|
-
* @returns Function to dispose the query and unsubscribe.
|
|
22
|
-
*/
|
|
23
|
-
run(onData: (value?: T[]) => void, onError: (err: Error) => void): Cb;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const QueryResult = Object.freeze({
|
|
27
|
-
fromPromise: <T>(run: (onDispose: (cb: Cb) => void) => Promise<T[]>): QueryResult<T> => {
|
|
28
|
-
return {
|
|
29
|
-
run: (onData, onError) => {
|
|
30
|
-
const cbs: Cb[] = [];
|
|
31
|
-
let disposed = false;
|
|
32
|
-
const dispose = () => {
|
|
33
|
-
cbs.forEach((cb) => cb());
|
|
34
|
-
disposed = true;
|
|
35
|
-
};
|
|
36
|
-
run((cb) => (disposed ? cb() : cbs.push(cb))).then(
|
|
37
|
-
(data) => {
|
|
38
|
-
if (disposed) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
onData(data);
|
|
42
|
-
},
|
|
43
|
-
(err) => {
|
|
44
|
-
dispose();
|
|
45
|
-
onError(err);
|
|
46
|
-
},
|
|
47
|
-
);
|
|
48
|
-
return dispose;
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
interface _Resolver<T> {
|
|
55
|
-
query(query: Query): QueryResult<T>;
|
|
56
|
-
}
|