@@ -240,6 +240,28 @@ function getObjectOrInterfaceFields(type) {
240
240
return keys ;
241
241
}
242
242
243
+ /**
244
+ * Get the annotations of an edge and convert them to string to be used in insert operations
245
+ * Would have prefered using createEdge, but we seem unable to pass a properly accesible "context variable"._id as parameter
246
+ * @param annotations
247
+ * @returns String
248
+ */
249
+ function getAnnotations ( annotations ) {
250
+ // Remeber that annotations should already have passed through getScalarsAndEnums
251
+ // So injections on field should not be possible
252
+ // The values need to be checked separatly.
253
+ let ret = '' ;
254
+ for ( let field in annotations ) {
255
+ if ( typeof annotations [ field ] === 'string' ) {
256
+ // Treat strings as strings
257
+ ret += `, ${ field } : "${ annotations [ field ] } "` ;
258
+ }
259
+ else
260
+ ret += `, ${ field } : ${ annotations [ field ] } ` ;
261
+ }
262
+ return ret ;
263
+ }
264
+
243
265
// ----------------------------------------------------------
244
266
245
267
async function getEdge ( parent , args , info ) {
@@ -301,15 +323,15 @@ async function getEdge(parent, args, info){
301
323
/*
302
324
TODO: We should probably call the createEdge function here (when we've defined it).
303
325
*/
304
- async function create ( isRoot , ctxt , data , returnType , info ) {
326
+ async function create ( isRoot , ctxt , data , returnType , info ) {
305
327
// define transaction object
306
- if ( ctxt . trans === undefined ) ctxt . trans = initTransaction ( ) ;
328
+ if ( ctxt . trans === undefined ) ctxt . trans = initTransaction ( ) ;
307
329
308
330
// is root op and mutatation is already queued
309
- if ( isRoot && ctxt . trans . queue [ info . path . key ] ) {
310
- if ( ctxt . trans . open ) await executeTransaction ( ctxt ) ;
311
- if ( ctxt . trans . error ) {
312
- if ( ctxt . trans . errorReported ) return null ;
331
+ if ( isRoot && ctxt . trans . queue [ info . path . key ] ) {
332
+ if ( ctxt . trans . open ) await executeTransaction ( ctxt ) ;
333
+ if ( ctxt . trans . error ) {
334
+ if ( ctxt . trans . errorReported ) return null ;
313
335
ctxt . trans . errorReported = true ;
314
336
throw ctxt . trans . error ;
315
337
}
@@ -338,18 +360,26 @@ async function create(isRoot, ctxt, data, returnType, info){
338
360
339
361
// for edges
340
362
let ob = getTypesAndInterfaces ( data , returnType ) ;
341
- for ( let fieldName in ob ) {
363
+ for ( let fieldName in ob ) {
342
364
let innerFieldType = graphql . getNamedType ( returnType . getFields ( ) [ fieldName ] . type ) ;
343
365
let edge = getEdgeCollectionName ( returnType . name , fieldName ) ;
344
366
ctxt . trans . write . add ( edge ) ;
345
367
let edgeCollection = asAQLVar ( `db.${ edge } ` ) ;
346
368
let values = Array . isArray ( ob [ fieldName ] ) ? ob [ fieldName ] : [ ob [ fieldName ] ] ; // treat as list even if only one value is present
347
369
348
- for ( let i in values ) {
370
+ for ( let i in values ) {
349
371
let value = values [ i ] ;
350
372
console . log ( value ) ;
351
- if ( graphql . isInterfaceType ( innerFieldType ) ) { // interface
352
- if ( value [ 'connect' ] ) {
373
+
374
+ // Prepare annotations
375
+ let annotations = null ;
376
+ if ( value [ 'annotations' ] ) {
377
+ annotations = getScalarsAndEnums ( value [ 'annotations' ] , info . schema . getType ( "_InputToAnnotate" + edge ) ) ;
378
+ annotations [ '_creationDate' ] = date . valueOf ( ) ;
379
+ }
380
+
381
+ if ( graphql . isInterfaceType ( innerFieldType ) ) { // interface
382
+ if ( value [ 'connect' ] ) {
353
383
validateType ( ctxt , value [ 'connect' ] , innerFieldType , info . schema ) ;
354
384
let typeToConnect = value [ 'connect' ] . split ( '/' ) [ 0 ] ;
355
385
// add edge
@@ -361,10 +391,14 @@ async function create(isRoot, ctxt, data, returnType, info){
361
391
} else {
362
392
// create
363
393
let key = Object . keys ( value ) [ 0 ] ;
394
+ if ( key == "annotations" ) {
395
+ // In case the user actually specifies the annotations before the edge
396
+ key = Object . keys ( value ) [ 1 ] ;
397
+ }
364
398
let typeToCreate = key . replace ( / ^ c r e a t e ( .+ ) $ / , '$1' ) ;
365
- let to = asAQLVar ( getVar ( ctxt ) ) ; // reference to the object to be added
399
+ let to = asAQLVar ( getVar ( ctxt ) ) ; // reference to the object to be addedd
366
400
await create ( false , ctxt , value [ key ] , info . schema . getType ( typeToCreate ) , info ) ;
367
- ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: ${ from } ._id, _to: ${ to } ._id } IN ${ edgeCollection } RETURN NEW\`);` ) ;
401
+ ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: ${ from } ._id, _to: ${ to } ._id ${ getAnnotations ( annotations ) } } IN ${ edgeCollection } RETURN NEW\`);` ) ;
368
402
}
369
403
} else { // type
370
404
if ( value [ 'connect' ] ) {
@@ -376,10 +410,11 @@ async function create(isRoot, ctxt, data, returnType, info){
376
410
ctxt . trans . code . push ( `} else { ` ) ;
377
411
ctxt . trans . code . push ( ` throw "${ value [ 'connect' ] } does not exist in ${ typeToConnect } ";` ) ;
378
412
ctxt . trans . code . push ( `}` ) ;
379
- } else { // create
413
+ } else { //
380
414
let to = asAQLVar ( getVar ( ctxt ) ) ; // reference to the object to be added
381
415
await create ( false , ctxt , value [ 'create' ] , innerFieldType , info ) ;
382
- ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: ${ from } ._id, _to: ${ to } ._id } IN ${ edgeCollection } RETURN NEW\`);` ) ;
416
+ console . log ( innerFieldType . name ) ;
417
+ ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: ${ from } ._id, _to: ${ to } ._id ${ getAnnotations ( annotations ) } } IN ${ edgeCollection } RETURN NEW\`);` ) ;
383
418
}
384
419
}
385
420
}
@@ -389,7 +424,7 @@ async function create(isRoot, ctxt, data, returnType, info){
389
424
addFinalDirectiveChecksForType ( ctxt , returnType , aql `${ asAQLVar ( resVar ) } ._id` , info . schema ) ;
390
425
391
426
// overwrite the current action
392
- if ( isRoot ) {
427
+ if ( isRoot ) {
393
428
ctxt . trans . code . push ( `result['${ info . path . key } '] = ${ resVar } ;` ) ; // add root result
394
429
ctxt . trans . queue [ info . path . key ] = true ; // indicate that this mutation op has been added to the transaction
395
430
getVar ( ctxt ) ; // increment varCounter
@@ -549,15 +584,15 @@ function validateType(ctxt, id, type, schema){
549
584
}
550
585
}
551
586
552
- async function update ( isRoot , ctxt , id , data , returnType , info ) {
587
+ async function update ( isRoot , ctxt , id , data , returnType , info ) {
553
588
// define transaction object
554
- if ( ctxt . trans === undefined ) ctxt . trans = initTransaction ( ) ;
589
+ if ( ctxt . trans === undefined ) ctxt . trans = initTransaction ( ) ;
555
590
556
591
// is root op and mutation is already queued
557
- if ( isRoot && ctxt . trans . queue [ info . path . key ] ) {
558
- if ( ctxt . trans . open ) await executeTransaction ( ctxt ) ;
559
- if ( ctxt . trans . error ) {
560
- if ( ctxt . trans . errorReported ) return null ;
592
+ if ( isRoot && ctxt . trans . queue [ info . path . key ] ) {
593
+ if ( ctxt . trans . open ) await executeTransaction ( ctxt ) ;
594
+ if ( ctxt . trans . error ) {
595
+ if ( ctxt . trans . errorReported ) return null ;
561
596
ctxt . trans . errorReported = true ;
562
597
throw ctxt . trans . error ;
563
598
}
@@ -569,24 +604,24 @@ async function update(isRoot, ctxt, id, data, returnType, info){
569
604
// 3) Add key check to transaction
570
605
let keyName = getKeyName ( returnType . name ) ;
571
606
let keyType = info . schema [ "_typeMap" ] [ keyName ] ;
572
- if ( keyType ) {
607
+ if ( keyType ) {
573
608
try {
574
609
let collection = db . collection ( returnType ) ;
575
610
const cursor = await db . query ( aql `FOR i IN ${ collection } FILTER(i._id == ${ id } ) RETURN i` ) ;
576
611
let doc = await cursor . next ( ) ;
577
- if ( doc == undefined ) {
612
+ if ( doc == undefined ) {
578
613
throw new ApolloError ( `ID ${ id } is not a document in the type ${ returnType } ` ) ;
579
614
}
580
615
581
616
let key = { } ;
582
- for ( let f in keyType . _fields ) {
617
+ for ( let f in keyType . _fields ) {
583
618
key [ f ] = doc [ f ] ;
584
- if ( data [ f ] !== undefined ) {
619
+ if ( data [ f ] !== undefined ) {
585
620
key [ f ] = data [ f ] ;
586
621
}
587
622
}
588
623
validateKey ( ctxt , key , returnType , info . schema , id ) ;
589
- } catch ( err ) {
624
+ } catch ( err ) {
590
625
throw new ApolloError ( err ) ;
591
626
}
592
627
}
@@ -619,6 +654,13 @@ async function update(isRoot, ctxt, id, data, returnType, info){
619
654
for ( let i in values ) {
620
655
let value = values [ i ] ;
621
656
657
+ // Prepare annotations
658
+ let annotations = null ;
659
+ if ( value [ 'annotations' ] ) {
660
+ annotations = getScalarsAndEnums ( value [ 'annotations' ] , info . schema . getType ( "_InputToAnnotate" + edge ) ) ;
661
+ annotations [ '_creationDate' ] = date . valueOf ( ) ;
662
+ }
663
+
622
664
if ( graphql . isInterfaceType ( nestedReturnType ) ) {
623
665
// interface field
624
666
if ( value [ 'connect' ] ) {
@@ -630,11 +672,11 @@ async function update(isRoot, ctxt, id, data, returnType, info){
630
672
// add edge
631
673
if ( ! disableEdgeValidation ) { // check the database
632
674
ctxt . trans . code . push ( `if(db._collection('${ typeToConnect } ').exists('${ value [ 'connect' ] } ')){` ) ;
633
- ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: "${ value [ 'connect' ] } " } IN ${ edgeCollection } RETURN NEW\`);` ) ;
675
+ ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: "${ value [ 'connect' ] } " ${ getAnnotations ( annotations ) } } IN ${ edgeCollection } RETURN NEW\`);` ) ;
634
676
ctxt . trans . code . push ( `} else { throw "${ value [ 'connect' ] } does not exist in ${ typeToConnect } "; }` ) ;
635
677
} else {
636
678
console . warn ( `Adding connection to ${ value [ 'connect' ] } in ${ edge } without validating ID` ) ;
637
- ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: "${ value [ 'connect' ] } " } IN ${ edgeCollection } RETURN NEW\`);` ) ;
679
+ ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: "${ value [ 'connect' ] } " ${ getAnnotations ( annotations ) } } IN ${ edgeCollection } RETURN NEW\`);` ) ;
638
680
}
639
681
} else {
640
682
// create
@@ -658,17 +700,17 @@ async function update(isRoot, ctxt, id, data, returnType, info){
658
700
// add edge
659
701
if ( ! disableEdgeValidation ) { // check the database
660
702
ctxt . trans . code . push ( `if(db._collection('${ typeToConnect } ').exists('${ value [ 'connect' ] } ')){` ) ;
661
- ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: "${ value [ 'connect' ] } " } IN ${ edgeCollection } RETURN NEW\`);` ) ;
703
+ ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: "${ value [ 'connect' ] } " ${ getAnnotations ( annotations ) } } IN ${ edgeCollection } RETURN NEW\`);` ) ;
662
704
ctxt . trans . code . push ( `} else { throw "${ value [ 'connect' ] } does not exist in ${ typeToConnect } "; }` ) ;
663
705
} else {
664
706
console . warn ( `Adding connection to ${ value [ 'connect' ] } in ${ edge } without validating ID` ) ;
665
- ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: "${ value [ 'connect' ] } " } IN ${ edgeCollection } RETURN NEW\`);` ) ;
707
+ ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: "${ value [ 'connect' ] } " ${ getAnnotations ( annotations ) } } IN ${ edgeCollection } RETURN NEW\`);` ) ;
666
708
}
667
709
} else {
668
710
// create
669
711
let to = asAQLVar ( getVar ( ctxt ) ) ; // reference to the object to be added
670
712
await create ( false , ctxt , value [ 'create' ] , nestedReturnType , info ) ;
671
- ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: ${ to } ._id } IN ${ edgeCollection } RETURN NEW\`);` ) ;
713
+ ctxt . trans . code . push ( `db._query(aql\`INSERT {_from: "${ id } ", _to: ${ to } ._id ${ getAnnotations ( annotations ) } } IN ${ edgeCollection } RETURN NEW\`);` ) ;
672
714
}
673
715
}
674
716
}
@@ -678,7 +720,7 @@ async function update(isRoot, ctxt, id, data, returnType, info){
678
720
addFinalDirectiveChecksForType ( ctxt , returnType , aql `${ asAQLVar ( resVar ) } ._id` , info . schema ) ;
679
721
680
722
// overwrite the current action
681
- if ( isRoot ) {
723
+ if ( isRoot ) {
682
724
ctxt . trans . code . push ( `result['${ info . path . key } '] = ${ resVar } .new;` ) ; // add root result
683
725
ctxt . trans . queue [ info . path . key ] = true ; // indicate that this mutation op has been added to the transaction
684
726
getVar ( ctxt ) ; // increment varCounter
0 commit comments