1
1
import neo4j , { Driver } from "neo4j-driver" ;
2
2
import { W3IDBuilder } from "w3id" ;
3
3
import { serializeValue , deserializeValue } from "./schema" ;
4
-
5
- type MetaEnvelope = {
6
- ontology : string ;
7
- payload : Record < string , any > ;
8
- acl : string [ ] ;
9
- } ;
10
-
11
- type Envelope = {
12
- id : string ;
13
- value : any ;
14
- ontology : string ;
15
- valueType : string ;
16
- } ;
17
-
4
+ import {
5
+ MetaEnvelope ,
6
+ Envelope ,
7
+ MetaEnvelopeResult ,
8
+ StoreMetaEnvelopeResult ,
9
+ SearchMetaEnvelopesResult ,
10
+ GetAllEnvelopesResult ,
11
+ } from "./types" ;
12
+
13
+ /**
14
+ * Service for managing meta-envelopes and their associated envelopes in Neo4j.
15
+ * Provides functionality for storing, retrieving, searching, and updating data
16
+ * with proper type handling and access control.
17
+ */
18
18
export class DbService {
19
- private driver : Driver ;
20
-
21
- constructor ( uri : string , user : string , password : string ) {
22
- this . driver = neo4j . driver ( uri , neo4j . auth . basic ( user , password ) ) ;
23
- }
24
-
19
+ /**
20
+ * Creates a new instance of the DbService.
21
+ * @param driver - The Neo4j driver instance
22
+ */
23
+ constructor ( private driver : Driver ) { }
24
+
25
+ /**
26
+ * Executes a Cypher query with the given parameters.
27
+ * @param query - The Cypher query to execute
28
+ * @param params - The parameters for the query
29
+ * @returns The result of the query execution
30
+ */
25
31
private async runQuery ( query : string , params : Record < string , any > ) {
26
32
const session = this . driver . session ( ) ;
27
33
try {
@@ -31,7 +37,18 @@ export class DbService {
31
37
}
32
38
}
33
39
34
- async storeMetaEnvelope ( meta : Omit < MetaEnvelope , "id" > , acl : string [ ] ) {
40
+ /**
41
+ * Stores a new meta-envelope and its associated envelopes.
42
+ * @param meta - The meta-envelope data (without ID)
43
+ * @param acl - The access control list for the meta-envelope
44
+ * @returns The created meta-envelope and its envelopes
45
+ */
46
+ async storeMetaEnvelope <
47
+ T extends Record < string , any > = Record < string , any > ,
48
+ > (
49
+ meta : Omit < MetaEnvelope < T > , "id" > ,
50
+ acl : string [ ] ,
51
+ ) : Promise < StoreMetaEnvelopeResult < T > > {
35
52
const w3id = await new W3IDBuilder ( ) . build ( ) ;
36
53
37
54
const cypher : string [ ] = [
@@ -44,7 +61,7 @@ export class DbService {
44
61
acl : acl ,
45
62
} ;
46
63
47
- const createdEnvelopes : Envelope [ ] = [ ] ;
64
+ const createdEnvelopes : Envelope < T [ keyof T ] > [ ] = [ ] ;
48
65
let counter = 0 ;
49
66
50
67
for ( const [ key , value ] of Object . entries ( meta . payload ) ) {
@@ -74,7 +91,7 @@ export class DbService {
74
91
createdEnvelopes . push ( {
75
92
id : envelopeId ,
76
93
ontology : key ,
77
- value : value ,
94
+ value : value as T [ keyof T ] ,
78
95
valueType,
79
96
} ) ;
80
97
@@ -93,12 +110,19 @@ export class DbService {
93
110
} ;
94
111
}
95
112
96
- async findMetaEnvelopesBySearchTerm (
113
+ /**
114
+ * Finds meta-envelopes containing the search term in any of their envelopes.
115
+ * Returns all envelopes from the matched meta-envelopes.
116
+ * @param ontology - The ontology to search within
117
+ * @param searchTerm - The term to search for
118
+ * @returns Array of matched meta-envelopes with their complete envelope sets
119
+ */
120
+ async findMetaEnvelopesBySearchTerm <
121
+ T extends Record < string , any > = Record < string , any > ,
122
+ > (
97
123
ontology : string ,
98
124
searchTerm : string ,
99
- ) : Promise <
100
- { id : string ; envelopes : any [ ] ; parsed : Record < string , any > } [ ]
101
- > {
125
+ ) : Promise < SearchMetaEnvelopesResult < T > > {
102
126
const result = await this . runQuery (
103
127
`
104
128
MATCH (m:MetaEnvelope { ontology: $ontology })-[:LINKS_TO]->(e:Envelope)
@@ -111,43 +135,53 @@ export class DbService {
111
135
END
112
136
WITH m
113
137
MATCH (m)-[:LINKS_TO]->(allEnvelopes:Envelope)
114
- RETURN m.id AS id, collect(allEnvelopes) AS envelopes
138
+ RETURN m.id AS id, m.ontology AS ontology, m.acl AS acl, collect(allEnvelopes) AS envelopes
115
139
` ,
116
140
{ ontology, term : searchTerm } ,
117
141
) ;
118
142
119
- return result . records . map ( ( record ) => {
120
- const envelopes = record . get ( "envelopes" ) . map ( ( node : any ) => {
121
- const properties = node . properties ;
122
- return {
123
- id : properties . id ,
124
- ontology : properties . ontology ,
125
- value : deserializeValue (
126
- properties . value ,
127
- properties . valueType ,
128
- ) ,
129
- valueType : properties . valueType ,
130
- } ;
131
- } ) ;
143
+ return result . records . map ( ( record ) : MetaEnvelopeResult < T > => {
144
+ const envelopes = record
145
+ . get ( "envelopes" )
146
+ . map ( ( node : any ) : Envelope < T [ keyof T ] > => {
147
+ const properties = node . properties ;
148
+ return {
149
+ id : properties . id ,
150
+ ontology : properties . ontology ,
151
+ value : deserializeValue (
152
+ properties . value ,
153
+ properties . valueType ,
154
+ ) as T [ keyof T ] ,
155
+ valueType : properties . valueType ,
156
+ } ;
157
+ } ) ;
132
158
133
- // Reconstruct the original payload structure
134
159
const parsed = envelopes . reduce (
135
- ( acc : Record < string , any > , envelope : Envelope ) => {
136
- acc [ envelope . ontology ] = envelope . value ;
160
+ ( acc : T , envelope : Envelope < T [ keyof T ] > ) => {
161
+ ( acc as any ) [ envelope . ontology ] = envelope . value ;
137
162
return acc ;
138
163
} ,
139
- { } ,
164
+ { } as T ,
140
165
) ;
141
166
142
167
return {
143
168
id : record . get ( "id" ) ,
169
+ ontology : record . get ( "ontology" ) ,
170
+ acl : record . get ( "acl" ) ,
144
171
envelopes,
145
172
parsed,
146
173
} ;
147
174
} ) ;
148
175
}
149
176
150
- async findMetaEnvelopeById ( id : string ) : Promise < any > {
177
+ /**
178
+ * Finds a meta-envelope by its ID.
179
+ * @param id - The ID of the meta-envelope to find
180
+ * @returns The meta-envelope with all its envelopes and parsed payload, or null if not found
181
+ */
182
+ async findMetaEnvelopeById <
183
+ T extends Record < string , any > = Record < string , any > ,
184
+ > ( id : string ) : Promise < MetaEnvelopeResult < T > | null > {
151
185
const result = await this . runQuery (
152
186
`
153
187
MATCH (m:MetaEnvelope { id: $id })-[:LINKS_TO]->(e:Envelope)
@@ -159,23 +193,27 @@ export class DbService {
159
193
if ( ! result . records [ 0 ] ) return null ;
160
194
161
195
const record = result . records [ 0 ] ;
162
- const envelopes = record . get ( "envelopes" ) . map ( ( node : any ) => {
163
- const properties = node . properties ;
164
- return {
165
- id : properties . id ,
166
- ontology : properties . ontology ,
167
- value : deserializeValue ( properties . value , properties . valueType ) ,
168
- valueType : properties . valueType ,
169
- } ;
170
- } ) ;
196
+ const envelopes = record
197
+ . get ( "envelopes" )
198
+ . map ( ( node : any ) : Envelope < T [ keyof T ] > => {
199
+ const properties = node . properties ;
200
+ return {
201
+ id : properties . id ,
202
+ ontology : properties . ontology ,
203
+ value : deserializeValue (
204
+ properties . value ,
205
+ properties . valueType ,
206
+ ) as T [ keyof T ] ,
207
+ valueType : properties . valueType ,
208
+ } ;
209
+ } ) ;
171
210
172
- // Reconstruct the original payload structure
173
211
const parsed = envelopes . reduce (
174
- ( acc : Record < string , any > , envelope : Envelope ) => {
175
- acc [ envelope . ontology ] = envelope . value ;
212
+ ( acc : T , envelope : Envelope < T [ keyof T ] > ) => {
213
+ ( acc as any ) [ envelope . ontology ] = envelope . value ;
176
214
return acc ;
177
215
} ,
178
- { } ,
216
+ { } as T ,
179
217
) ;
180
218
181
219
return {
@@ -187,6 +225,11 @@ export class DbService {
187
225
} ;
188
226
}
189
227
228
+ /**
229
+ * Finds all meta-envelope IDs for a given ontology.
230
+ * @param ontology - The ontology to search for
231
+ * @returns Array of meta-envelope IDs
232
+ */
190
233
async findMetaEnvelopesByOntology ( ontology : string ) : Promise < string [ ] > {
191
234
const result = await this . runQuery (
192
235
`
@@ -199,6 +242,10 @@ export class DbService {
199
242
return result . records . map ( ( r ) => r . get ( "id" ) ) ;
200
243
}
201
244
245
+ /**
246
+ * Deletes a meta-envelope and all its associated envelopes.
247
+ * @param id - The ID of the meta-envelope to delete
248
+ */
202
249
async deleteMetaEnvelope ( id : string ) : Promise < void > {
203
250
await this . runQuery (
204
251
`
@@ -209,9 +256,14 @@ export class DbService {
209
256
) ;
210
257
}
211
258
212
- async updateEnvelopeValue (
259
+ /**
260
+ * Updates the value of an envelope.
261
+ * @param envelopeId - The ID of the envelope to update
262
+ * @param newValue - The new value to set
263
+ */
264
+ async updateEnvelopeValue < T = any > (
213
265
envelopeId : string ,
214
- newValue : any ,
266
+ newValue : T ,
215
267
) : Promise < void > {
216
268
const { value : storedValue , type : valueType } =
217
269
serializeValue ( newValue ) ;
@@ -225,20 +277,30 @@ export class DbService {
225
277
) ;
226
278
}
227
279
228
- async getAllEnvelopes ( ) : Promise < Envelope [ ] > {
280
+ /**
281
+ * Retrieves all envelopes in the system.
282
+ * @returns Array of all envelopes
283
+ */
284
+ async getAllEnvelopes < T = any > ( ) : Promise < GetAllEnvelopesResult < T > > {
229
285
const result = await this . runQuery ( `MATCH (e:Envelope) RETURN e` , { } ) ;
230
- return result . records . map ( ( r ) => {
286
+ return result . records . map ( ( r ) : Envelope < T > => {
231
287
const node = r . get ( "e" ) ;
232
288
const properties = node . properties ;
233
289
return {
234
290
id : properties . id ,
235
291
ontology : properties . ontology ,
236
- value : deserializeValue ( properties . value , properties . valueType ) ,
292
+ value : deserializeValue (
293
+ properties . value ,
294
+ properties . valueType ,
295
+ ) as T ,
237
296
valueType : properties . valueType ,
238
297
} ;
239
298
} ) ;
240
299
}
241
300
301
+ /**
302
+ * Closes the database connection.
303
+ */
242
304
async close ( ) : Promise < void > {
243
305
await this . driver . close ( ) ;
244
306
}
0 commit comments