@medicine-wheel/storage-provider 0.4.13 → 0.5.0
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/index.d.ts +2 -1
- package/dist/index.js +2 -0
- package/dist/interface.d.ts +44 -0
- package/dist/interface.js +37 -1
- package/dist/jsonl.d.ts +5 -1
- package/dist/jsonl.js +70 -0
- package/dist/neon.d.ts +5 -1
- package/dist/neon.js +73 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* const node = await store.getNode('elder-1');
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
|
-
export type { StorageProvider, RelationalNode, RelationalEdge, CeremonyLog, WeaveRecord, WeaveSyncState, InquiryWeaveFilters, PlanPerspectiveRecord, PlanPerspectiveEpisode, PlanPerspectiveFilters, ProviderType, } from './interface.js';
|
|
18
|
+
export type { StorageProvider, RelationalNode, RelationalEdge, CeremonyLog, WeaveRecord, WeaveSyncState, InquiryWeaveFilters, PlanPerspectiveRecord, PlanPerspectiveEpisode, PlanPerspectiveFilters, ProviderType, NodePatch, EdgePatch, } from './interface.js';
|
|
19
|
+
export { NodeNotFoundError, EdgeNotFoundError, NodeHasRelationsError, } from './interface.js';
|
|
19
20
|
export { mergePlanPerspectiveRecords, unionPlanPerspectiveEpisodes, matchesPlanPerspectiveFilters, } from './plan-perspectives.js';
|
|
20
21
|
export { createProvider, detectProvider } from './factory.js';
|
|
21
22
|
export { JsonlProvider } from './jsonl.js';
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* const node = await store.getNode('elder-1');
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
|
+
// Typed errors (thrown by update/delete operations)
|
|
19
|
+
export { NodeNotFoundError, EdgeNotFoundError, NodeHasRelationsError, } from './interface.js';
|
|
18
20
|
// Plan Perspective merge/filter semantics (shared across providers)
|
|
19
21
|
export { mergePlanPerspectiveRecords, unionPlanPerspectiveEpisodes, matchesPlanPerspectiveFilters, } from './plan-perspectives.js';
|
|
20
22
|
// Factory
|
package/dist/interface.d.ts
CHANGED
|
@@ -13,6 +13,42 @@ export interface RelationalEdge extends Omit<OntologyRelationalEdge, 'id'> {
|
|
|
13
13
|
last_ceremony?: string;
|
|
14
14
|
}
|
|
15
15
|
export type CeremonyLog = OntologyCeremonyLog;
|
|
16
|
+
/** Partial update for a node. `direction: null` releases the node from its direction. */
|
|
17
|
+
export interface NodePatch {
|
|
18
|
+
name?: string;
|
|
19
|
+
type?: NodeType;
|
|
20
|
+
description?: string;
|
|
21
|
+
direction?: DirectionName | null;
|
|
22
|
+
metadata?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/** Partial update for an edge (identified by from_id + to_id). */
|
|
25
|
+
export interface EdgePatch {
|
|
26
|
+
relationship_type?: string;
|
|
27
|
+
strength?: number;
|
|
28
|
+
ceremony_honored?: boolean;
|
|
29
|
+
obligations?: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare class NodeNotFoundError extends Error {
|
|
32
|
+
readonly nodeId: string;
|
|
33
|
+
readonly code = "NODE_NOT_FOUND";
|
|
34
|
+
constructor(nodeId: string);
|
|
35
|
+
}
|
|
36
|
+
export declare class EdgeNotFoundError extends Error {
|
|
37
|
+
readonly fromId: string;
|
|
38
|
+
readonly toId: string;
|
|
39
|
+
readonly code = "EDGE_NOT_FOUND";
|
|
40
|
+
constructor(fromId: string, toId: string);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Deleting a node with living relations is refused: relational accountability
|
|
44
|
+
* means severing each relation consciously before releasing the node.
|
|
45
|
+
*/
|
|
46
|
+
export declare class NodeHasRelationsError extends Error {
|
|
47
|
+
readonly nodeId: string;
|
|
48
|
+
readonly relationCount: number;
|
|
49
|
+
readonly code = "NODE_HAS_RELATIONS";
|
|
50
|
+
constructor(nodeId: string, relationCount: number);
|
|
51
|
+
}
|
|
16
52
|
export type WeaveSyncState = 'never-synced' | 'in-sync' | 'stale' | 'episode-copy-diverged';
|
|
17
53
|
export interface WeaveRecord extends Record<string, unknown> {
|
|
18
54
|
id: string;
|
|
@@ -110,11 +146,19 @@ export interface StorageProvider {
|
|
|
110
146
|
getNodesByType(type: NodeType): Promise<RelationalNode[]>;
|
|
111
147
|
getNodesByDirection(direction: DirectionName): Promise<RelationalNode[]>;
|
|
112
148
|
getAllNodes(limit?: number): Promise<RelationalNode[]>;
|
|
149
|
+
/** Throws NodeNotFoundError when the node does not exist. */
|
|
150
|
+
updateNode(id: string, patch: NodePatch): Promise<RelationalNode>;
|
|
151
|
+
/** Throws NodeNotFoundError or NodeHasRelationsError (refusal, never cascade). */
|
|
152
|
+
deleteNode(id: string): Promise<void>;
|
|
113
153
|
createEdge(edge: RelationalEdge): Promise<void>;
|
|
114
154
|
getEdge(fromId: string, toId: string): Promise<RelationalEdge | null>;
|
|
115
155
|
getAllEdges(limit?: number): Promise<RelationalEdge[]>;
|
|
116
156
|
getRelatedNodes(nodeId: string, direction?: 'from' | 'to' | 'both'): Promise<string[]>;
|
|
117
157
|
updateEdgeCeremony(fromId: string, toId: string, ceremonyId: string): Promise<void>;
|
|
158
|
+
/** Throws EdgeNotFoundError when no relation exists between the pair. */
|
|
159
|
+
updateEdge(fromId: string, toId: string, patch: EdgePatch): Promise<RelationalEdge>;
|
|
160
|
+
/** Throws EdgeNotFoundError when no relation exists between the pair. */
|
|
161
|
+
deleteEdge(fromId: string, toId: string): Promise<void>;
|
|
118
162
|
logCeremony(ceremony: CeremonyLog): Promise<void>;
|
|
119
163
|
getCeremony(id: string): Promise<CeremonyLog | null>;
|
|
120
164
|
getCeremoniesTimeline(limit?: number): Promise<CeremonyLog[]>;
|
package/dist/interface.js
CHANGED
|
@@ -4,4 +4,40 @@
|
|
|
4
4
|
* Abstract interface for Medicine Wheel data persistence.
|
|
5
5
|
* Implementations: JsonlProvider (local/default), NeonProvider (Postgres), RedisProvider (future)
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
// ── Typed Errors ──
|
|
8
|
+
// Providers throw these so API layers can answer with honest status codes.
|
|
9
|
+
export class NodeNotFoundError extends Error {
|
|
10
|
+
nodeId;
|
|
11
|
+
code = 'NODE_NOT_FOUND';
|
|
12
|
+
constructor(nodeId) {
|
|
13
|
+
super(`Node not found: ${nodeId}`);
|
|
14
|
+
this.nodeId = nodeId;
|
|
15
|
+
this.name = 'NodeNotFoundError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class EdgeNotFoundError extends Error {
|
|
19
|
+
fromId;
|
|
20
|
+
toId;
|
|
21
|
+
code = 'EDGE_NOT_FOUND';
|
|
22
|
+
constructor(fromId, toId) {
|
|
23
|
+
super(`Relation not found between ${fromId} and ${toId}`);
|
|
24
|
+
this.fromId = fromId;
|
|
25
|
+
this.toId = toId;
|
|
26
|
+
this.name = 'EdgeNotFoundError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Deleting a node with living relations is refused: relational accountability
|
|
31
|
+
* means severing each relation consciously before releasing the node.
|
|
32
|
+
*/
|
|
33
|
+
export class NodeHasRelationsError extends Error {
|
|
34
|
+
nodeId;
|
|
35
|
+
relationCount;
|
|
36
|
+
code = 'NODE_HAS_RELATIONS';
|
|
37
|
+
constructor(nodeId, relationCount) {
|
|
38
|
+
super(`This node holds ${relationCount} relation${relationCount === 1 ? '' : 's'} — release them first`);
|
|
39
|
+
this.nodeId = nodeId;
|
|
40
|
+
this.relationCount = relationCount;
|
|
41
|
+
this.name = 'NodeHasRelationsError';
|
|
42
|
+
}
|
|
43
|
+
}
|
package/dist/jsonl.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DirectionName, NodeType, CeremonyType } from '@medicine-wheel/ontology-core';
|
|
2
|
-
import type { StorageProvider, RelationalNode, RelationalEdge, CeremonyLog, WeaveRecord, InquiryWeaveFilters, PlanPerspectiveRecord, PlanPerspectiveFilters } from './interface.js';
|
|
2
|
+
import type { StorageProvider, RelationalNode, RelationalEdge, CeremonyLog, WeaveRecord, InquiryWeaveFilters, PlanPerspectiveRecord, PlanPerspectiveFilters, NodePatch, EdgePatch } from './interface.js';
|
|
3
3
|
export declare class JsonlProvider implements StorageProvider {
|
|
4
4
|
readonly name = "jsonl";
|
|
5
5
|
readonly dataDir: string;
|
|
@@ -16,11 +16,15 @@ export declare class JsonlProvider implements StorageProvider {
|
|
|
16
16
|
getNodesByType(type: NodeType): Promise<RelationalNode[]>;
|
|
17
17
|
getNodesByDirection(direction: DirectionName): Promise<RelationalNode[]>;
|
|
18
18
|
getAllNodes(limit?: number): Promise<RelationalNode[]>;
|
|
19
|
+
updateNode(id: string, patch: NodePatch): Promise<RelationalNode>;
|
|
20
|
+
deleteNode(id: string): Promise<void>;
|
|
19
21
|
createEdge(edge: RelationalEdge): Promise<void>;
|
|
20
22
|
getEdge(fromId: string, toId: string): Promise<RelationalEdge | null>;
|
|
21
23
|
getRelatedNodes(nodeId: string, direction?: 'from' | 'to' | 'both'): Promise<string[]>;
|
|
22
24
|
getAllEdges(limit?: number): Promise<RelationalEdge[]>;
|
|
23
25
|
updateEdgeCeremony(fromId: string, toId: string, ceremonyId: string): Promise<void>;
|
|
26
|
+
updateEdge(fromId: string, toId: string, patch: EdgePatch): Promise<RelationalEdge>;
|
|
27
|
+
deleteEdge(fromId: string, toId: string): Promise<void>;
|
|
24
28
|
logCeremony(ceremony: CeremonyLog): Promise<void>;
|
|
25
29
|
getCeremony(id: string): Promise<CeremonyLog | null>;
|
|
26
30
|
getCeremoniesTimeline(limit?: number): Promise<CeremonyLog[]>;
|
package/dist/jsonl.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { randomUUID } from 'crypto';
|
|
4
|
+
import { NodeNotFoundError, EdgeNotFoundError, NodeHasRelationsError, } from './interface.js';
|
|
4
5
|
import { mergePlanPerspectiveRecords, matchesPlanPerspectiveFilters, } from './plan-perspectives.js';
|
|
5
6
|
export class JsonlProvider {
|
|
6
7
|
name = 'jsonl';
|
|
@@ -49,6 +50,42 @@ export class JsonlProvider {
|
|
|
49
50
|
.slice(0, limit)
|
|
50
51
|
.map((node) => this.parseNode(node));
|
|
51
52
|
}
|
|
53
|
+
async updateNode(id, patch) {
|
|
54
|
+
return withWriteLock(this.nodesFile, () => {
|
|
55
|
+
const nodes = this.readNodes();
|
|
56
|
+
const index = nodes.findIndex((candidate) => candidate.id === id);
|
|
57
|
+
if (index === -1)
|
|
58
|
+
throw new NodeNotFoundError(id);
|
|
59
|
+
const current = nodes[index];
|
|
60
|
+
const next = {
|
|
61
|
+
...current,
|
|
62
|
+
...(patch.name !== undefined ? { name: patch.name } : {}),
|
|
63
|
+
...(patch.type !== undefined ? { type: patch.type } : {}),
|
|
64
|
+
...(patch.description !== undefined ? { description: patch.description } : {}),
|
|
65
|
+
...(patch.metadata !== undefined ? { metadata: patch.metadata } : {}),
|
|
66
|
+
updated_at: new Date().toISOString(),
|
|
67
|
+
};
|
|
68
|
+
if (patch.direction !== undefined) {
|
|
69
|
+
next.direction = patch.direction === null ? undefined : patch.direction;
|
|
70
|
+
}
|
|
71
|
+
nodes[index] = next;
|
|
72
|
+
writeJsonl(this.nodesFile, nodes);
|
|
73
|
+
return this.parseNode(next);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async deleteNode(id) {
|
|
77
|
+
await withWriteLock(this.nodesFile, () => {
|
|
78
|
+
const nodes = this.readNodes();
|
|
79
|
+
if (!nodes.some((candidate) => candidate.id === id)) {
|
|
80
|
+
throw new NodeNotFoundError(id);
|
|
81
|
+
}
|
|
82
|
+
const relationCount = this.readEdges().filter((edge) => edge.from_id === id || edge.to_id === id).length;
|
|
83
|
+
if (relationCount > 0) {
|
|
84
|
+
throw new NodeHasRelationsError(id, relationCount);
|
|
85
|
+
}
|
|
86
|
+
writeJsonl(this.nodesFile, nodes.filter((candidate) => candidate.id !== id));
|
|
87
|
+
});
|
|
88
|
+
}
|
|
52
89
|
async createEdge(edge) {
|
|
53
90
|
await this.upsertEdge({
|
|
54
91
|
...edge,
|
|
@@ -92,6 +129,38 @@ export class JsonlProvider {
|
|
|
92
129
|
writeJsonl(this.edgesFile, nextEdges);
|
|
93
130
|
});
|
|
94
131
|
}
|
|
132
|
+
async updateEdge(fromId, toId, patch) {
|
|
133
|
+
return withWriteLock(this.edgesFile, () => {
|
|
134
|
+
const edges = this.readEdges();
|
|
135
|
+
const index = edges.findIndex((candidate) => candidate.from_id === fromId && candidate.to_id === toId);
|
|
136
|
+
if (index === -1)
|
|
137
|
+
throw new EdgeNotFoundError(fromId, toId);
|
|
138
|
+
const next = {
|
|
139
|
+
...edges[index],
|
|
140
|
+
...(patch.relationship_type !== undefined
|
|
141
|
+
? { relationship_type: patch.relationship_type }
|
|
142
|
+
: {}),
|
|
143
|
+
...(patch.strength !== undefined ? { strength: patch.strength } : {}),
|
|
144
|
+
...(patch.ceremony_honored !== undefined
|
|
145
|
+
? { ceremony_honored: patch.ceremony_honored }
|
|
146
|
+
: {}),
|
|
147
|
+
...(patch.obligations !== undefined ? { obligations: patch.obligations } : {}),
|
|
148
|
+
};
|
|
149
|
+
edges[index] = next;
|
|
150
|
+
writeJsonl(this.edgesFile, edges);
|
|
151
|
+
return this.parseEdge(next);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
async deleteEdge(fromId, toId) {
|
|
155
|
+
await withWriteLock(this.edgesFile, () => {
|
|
156
|
+
const edges = this.readEdges();
|
|
157
|
+
const remaining = edges.filter((candidate) => !(candidate.from_id === fromId && candidate.to_id === toId));
|
|
158
|
+
if (remaining.length === edges.length) {
|
|
159
|
+
throw new EdgeNotFoundError(fromId, toId);
|
|
160
|
+
}
|
|
161
|
+
writeJsonl(this.edgesFile, remaining);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
95
164
|
async logCeremony(ceremony) {
|
|
96
165
|
await this.upsertById(this.ceremoniesFile, ceremony);
|
|
97
166
|
}
|
|
@@ -193,6 +262,7 @@ export class JsonlProvider {
|
|
|
193
262
|
}
|
|
194
263
|
parseEdge(edge) {
|
|
195
264
|
return {
|
|
265
|
+
id: edge.id ?? `${edge.from_id}:${edge.to_id}`,
|
|
196
266
|
from_id: edge.from_id,
|
|
197
267
|
to_id: edge.to_id,
|
|
198
268
|
relationship_type: edge.relationship_type,
|
package/dist/neon.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Neon (Postgres) Storage Provider
|
|
3
3
|
*/
|
|
4
4
|
import type { DirectionName, NodeType, CeremonyType } from '@medicine-wheel/ontology-core';
|
|
5
|
-
import type { StorageProvider, RelationalNode, RelationalEdge, CeremonyLog, WeaveRecord, InquiryWeaveFilters, PlanPerspectiveRecord, PlanPerspectiveFilters } from './interface.js';
|
|
5
|
+
import type { StorageProvider, RelationalNode, RelationalEdge, CeremonyLog, WeaveRecord, InquiryWeaveFilters, PlanPerspectiveRecord, PlanPerspectiveFilters, NodePatch, EdgePatch } from './interface.js';
|
|
6
6
|
export declare class NeonProvider implements StorageProvider {
|
|
7
7
|
readonly name = "neon";
|
|
8
8
|
private sql;
|
|
@@ -14,12 +14,16 @@ export declare class NeonProvider implements StorageProvider {
|
|
|
14
14
|
getNodesByType(type: NodeType): Promise<RelationalNode[]>;
|
|
15
15
|
getNodesByDirection(direction: DirectionName): Promise<RelationalNode[]>;
|
|
16
16
|
getAllNodes(limit?: number): Promise<RelationalNode[]>;
|
|
17
|
+
updateNode(id: string, patch: NodePatch): Promise<RelationalNode>;
|
|
18
|
+
deleteNode(id: string): Promise<void>;
|
|
17
19
|
private parseNode;
|
|
18
20
|
createEdge(edge: RelationalEdge): Promise<void>;
|
|
19
21
|
getEdge(fromId: string, toId: string): Promise<RelationalEdge | null>;
|
|
20
22
|
getRelatedNodes(nodeId: string, direction?: 'from' | 'to' | 'both'): Promise<string[]>;
|
|
21
23
|
getAllEdges(limit?: number): Promise<RelationalEdge[]>;
|
|
22
24
|
updateEdgeCeremony(fromId: string, toId: string, ceremonyId: string): Promise<void>;
|
|
25
|
+
updateEdge(fromId: string, toId: string, patch: EdgePatch): Promise<RelationalEdge>;
|
|
26
|
+
deleteEdge(fromId: string, toId: string): Promise<void>;
|
|
23
27
|
private parseEdge;
|
|
24
28
|
logCeremony(ceremony: CeremonyLog): Promise<void>;
|
|
25
29
|
getCeremony(id: string): Promise<CeremonyLog | null>;
|
package/dist/neon.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Neon (Postgres) Storage Provider
|
|
3
3
|
*/
|
|
4
|
+
import { NodeNotFoundError, EdgeNotFoundError, NodeHasRelationsError, } from './interface.js';
|
|
4
5
|
import { mergePlanPerspectiveRecords, matchesPlanPerspectiveFilters, } from './plan-perspectives.js';
|
|
5
6
|
export class NeonProvider {
|
|
6
7
|
name = 'neon';
|
|
@@ -56,6 +57,45 @@ export class NeonProvider {
|
|
|
56
57
|
const rows = await this.db `SELECT * FROM nodes ORDER BY created_at DESC LIMIT ${limit}`;
|
|
57
58
|
return rows.map((row) => this.parseNode(row));
|
|
58
59
|
}
|
|
60
|
+
async updateNode(id, patch) {
|
|
61
|
+
const existing = await this.getNode(id);
|
|
62
|
+
if (!existing)
|
|
63
|
+
throw new NodeNotFoundError(id);
|
|
64
|
+
const next = {
|
|
65
|
+
...existing,
|
|
66
|
+
...(patch.name !== undefined ? { name: patch.name } : {}),
|
|
67
|
+
...(patch.type !== undefined ? { type: patch.type } : {}),
|
|
68
|
+
...(patch.description !== undefined ? { description: patch.description } : {}),
|
|
69
|
+
...(patch.metadata !== undefined ? { metadata: patch.metadata } : {}),
|
|
70
|
+
updated_at: new Date().toISOString(),
|
|
71
|
+
};
|
|
72
|
+
if (patch.direction !== undefined) {
|
|
73
|
+
next.direction = patch.direction === null ? undefined : patch.direction;
|
|
74
|
+
}
|
|
75
|
+
await this.db `
|
|
76
|
+
UPDATE nodes SET
|
|
77
|
+
name = ${next.name},
|
|
78
|
+
type = ${next.type},
|
|
79
|
+
description = ${next.description ?? ''},
|
|
80
|
+
direction = ${next.direction || null},
|
|
81
|
+
metadata = ${JSON.stringify(next.metadata)},
|
|
82
|
+
updated_at = ${next.updated_at}
|
|
83
|
+
WHERE id = ${id}
|
|
84
|
+
`;
|
|
85
|
+
return next;
|
|
86
|
+
}
|
|
87
|
+
async deleteNode(id) {
|
|
88
|
+
const existing = await this.db `SELECT id FROM nodes WHERE id = ${id}`;
|
|
89
|
+
if (existing.length === 0)
|
|
90
|
+
throw new NodeNotFoundError(id);
|
|
91
|
+
const counts = await this.db `
|
|
92
|
+
SELECT COUNT(*)::int AS count FROM edges WHERE from_id = ${id} OR to_id = ${id}
|
|
93
|
+
`;
|
|
94
|
+
const relationCount = Number(counts[0]?.count ?? 0);
|
|
95
|
+
if (relationCount > 0)
|
|
96
|
+
throw new NodeHasRelationsError(id, relationCount);
|
|
97
|
+
await this.db `DELETE FROM nodes WHERE id = ${id}`;
|
|
98
|
+
}
|
|
59
99
|
parseNode(row) {
|
|
60
100
|
return {
|
|
61
101
|
id: row.id,
|
|
@@ -115,8 +155,41 @@ export class NeonProvider {
|
|
|
115
155
|
WHERE from_id = ${fromId} AND to_id = ${toId}
|
|
116
156
|
`;
|
|
117
157
|
}
|
|
158
|
+
async updateEdge(fromId, toId, patch) {
|
|
159
|
+
const existing = await this.getEdge(fromId, toId);
|
|
160
|
+
if (!existing)
|
|
161
|
+
throw new EdgeNotFoundError(fromId, toId);
|
|
162
|
+
const next = {
|
|
163
|
+
...existing,
|
|
164
|
+
...(patch.relationship_type !== undefined
|
|
165
|
+
? { relationship_type: patch.relationship_type }
|
|
166
|
+
: {}),
|
|
167
|
+
...(patch.strength !== undefined ? { strength: patch.strength } : {}),
|
|
168
|
+
...(patch.ceremony_honored !== undefined
|
|
169
|
+
? { ceremony_honored: patch.ceremony_honored }
|
|
170
|
+
: {}),
|
|
171
|
+
...(patch.obligations !== undefined ? { obligations: patch.obligations } : {}),
|
|
172
|
+
};
|
|
173
|
+
await this.db `
|
|
174
|
+
UPDATE edges SET
|
|
175
|
+
relationship_type = ${next.relationship_type},
|
|
176
|
+
strength = ${next.strength},
|
|
177
|
+
ceremony_honored = ${next.ceremony_honored},
|
|
178
|
+
obligations = ${JSON.stringify(next.obligations)}
|
|
179
|
+
WHERE from_id = ${fromId} AND to_id = ${toId}
|
|
180
|
+
`;
|
|
181
|
+
return next;
|
|
182
|
+
}
|
|
183
|
+
async deleteEdge(fromId, toId) {
|
|
184
|
+
const deleted = await this.db `
|
|
185
|
+
DELETE FROM edges WHERE from_id = ${fromId} AND to_id = ${toId} RETURNING from_id
|
|
186
|
+
`;
|
|
187
|
+
if (deleted.length === 0)
|
|
188
|
+
throw new EdgeNotFoundError(fromId, toId);
|
|
189
|
+
}
|
|
118
190
|
parseEdge(row) {
|
|
119
191
|
return {
|
|
192
|
+
id: `${row.from_id}:${row.to_id}`,
|
|
120
193
|
from_id: row.from_id,
|
|
121
194
|
to_id: row.to_id,
|
|
122
195
|
relationship_type: row.relationship_type,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@medicine-wheel/storage-provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@neondatabase/serverless": "^0.10.0",
|
|
18
18
|
"@upstash/redis": "^1.34.3",
|
|
19
|
-
"@medicine-wheel/ontology-core": "^0.
|
|
19
|
+
"@medicine-wheel/ontology-core": "^0.5.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"typescript": "^5.7.0"
|