@@ -2,7 +2,7 @@ const graphql = require('graphql');
2
2
const arangojs = require ( "arangojs" ) ;
3
3
const aql = arangojs . aql ;
4
4
const { makeExecutableSchema } = require ( 'graphql-tools' ) ;
5
- const { ApolloError } = require ( 'apollo-server' ) ;
5
+ const { ApolloError, gql } = require ( 'apollo-server' ) ;
6
6
const waitOn = require ( 'wait-on' ) ;
7
7
8
8
let db ;
@@ -62,9 +62,9 @@ module.exports = {
62
62
} ;
63
63
64
64
async function init ( args ) {
65
- let typeDefs = args . typeDefs ;
65
+ let typeDefs = gql ` ${ args . baseSchema } ` ;
66
66
let dbName = args . dbName || 'dev-db' ;
67
- let url = args . url || 'http://localhost:8529' ;
67
+ let url = args . dbUrl || 'http://localhost:8529' ;
68
68
let drop = args . drop || false ;
69
69
disableDirectivesChecking = args [ 'disableDirectivesChecking' ] || false ;
70
70
disableEdgeValidation = args [ 'disableEdgeValidation' ] || false ;
@@ -83,7 +83,7 @@ async function init(args) {
83
83
console . info ( `ArangoDB is now available at ${ url } ` ) ;
84
84
85
85
// if drop is set
86
- dblist = await db . listDatabases ( ) ;
86
+ let dblist = await db . listDatabases ( ) ;
87
87
if ( drop && dblist . includes ( dbName ) ) {
88
88
await db . dropDatabase ( dbName ) . then (
89
89
( ) => console . info ( `Database ${ dbName } dropped.` ) ,
@@ -324,11 +324,7 @@ function createEdge(isRoot, ctxt, varOrSourceID, sourceType, sourceField, varOrT
324
324
// prepare annotations
325
325
if ( annotations === null || annotations === undefined ) annotations = { } ;
326
326
// substitute fields defined by exported variables
327
- annotations = substituteExportedVariables ( annotations , ctxt ) ;
328
- let annotationType = info . schema . getType ( `_InputToAnnotate${ collectionName } ` ) ;
329
- if ( annotationType ) { // RK: Should we be able to skip this due to previous validation?
330
- annotations = getScalarsAndEnums ( annotations , info . schema . getType ( annotationType ) ) ;
331
- }
327
+ const substitutedFields = substituteExportedVariables ( annotations , ctxt ) ;
332
328
333
329
// create a new variable if resVar was not defined by the calling function
334
330
resVar = resVar !== null ? resVar : createVar ( ctxt ) ;
@@ -355,7 +351,7 @@ function createEdge(isRoot, ctxt, varOrSourceID, sourceType, sourceField, varOrT
355
351
validateEdge ( ctxt , source , sourceType , sourceField , target , targetType , info , validateSource , validateTarget ) ;
356
352
357
353
// insert edge
358
- ctxt . trans . code . push ( `let ${ resVar } = db._query(aql\`INSERT MERGE(${ asAQLVar ( docVar ) } , {'_from': ${ source } , '_to': ${ target } }) IN ${ asAQLVar ( collectionVar ) } RETURN NEW\`).next();` ) ;
354
+ ctxt . trans . code . push ( `let ${ resVar } = db._query(aql\`INSERT MERGE(${ asAQLVar ( docVar ) } , ${ stringifyImportedFields ( substitutedFields ) } , {'_from': ${ source } , '_to': ${ target } }) IN ${ asAQLVar ( collectionVar ) } RETURN NEW\`).next();` ) ;
359
355
360
356
// add exported variables from selection fields for root only
361
357
addExportedVariables ( isRoot , resVar , info , ctxt ) ;
@@ -475,13 +471,16 @@ function updateEdge(isRoot, ctxt, id, data, edgeName, inputToUpdateType, info, r
475
471
const collectionVar = getCollectionVar ( edgeName , ctxt , true ) ;
476
472
ctxt . trans . code . push ( `\n\t/* update edge ${ edgeName } */` ) ;
477
473
474
+ // substitute fields defined by exported variables
475
+ const substitutedFields = substituteExportedVariables ( data , ctxt ) ;
476
+
478
477
// define doc
479
478
const doc = getScalarsAndEnums ( data , info . schema . getType ( inputToUpdateType ) ) ; ;
480
479
doc [ '_lastUpdateDate' ] = new Date ( ) . valueOf ( ) ;
481
480
const docVar = addParameterVar ( ctxt , createParamVar ( ctxt ) , doc ) ;
482
481
const idVar = addParameterVar ( ctxt , createParamVar ( ctxt ) , id ) ;
483
482
484
- ctxt . trans . code . push ( `let ${ resVar } = db._query(aql\`UPDATE PARSE_IDENTIFIER(${ asAQLVar ( idVar ) } ).key WITH ${ asAQLVar ( docVar ) } IN ${ asAQLVar ( collectionVar ) } RETURN NEW\`).next();` ) ;
483
+ ctxt . trans . code . push ( `let ${ resVar } = db._query(aql\`UPDATE PARSE_IDENTIFIER(${ asAQLVar ( idVar ) } ).key WITH MERGE( ${ asAQLVar ( docVar ) } , ${ stringifyImportedFields ( substitutedFields ) } ) IN ${ asAQLVar ( collectionVar ) } RETURN NEW\`).next();` ) ;
485
484
486
485
//directives handling is not needed for edge updates as they can not have directives as of current
487
486
@@ -581,7 +580,7 @@ function exportSelection(isRoot, resVar, selection, info, ctxt){
581
580
*/
582
581
function substituteExportedVariables ( data , ctxt ) {
583
582
const substitutes = { } ;
584
- Object . entries ( data ) . forEach ( ( entry ) => {
583
+ for ( let entry of Object . entries ( data ) ) {
585
584
const fieldName = entry [ 0 ] ;
586
585
const value = entry [ 1 ] ;
587
586
// if value is an object it must be a variable
@@ -597,7 +596,7 @@ function substituteExportedVariables(data, ctxt){
597
596
}
598
597
}
599
598
}
600
- } ) ;
599
+ }
601
600
return substitutes ;
602
601
}
603
602
@@ -827,7 +826,7 @@ function deleteObject(isRoot, ctxt, varOrID, typeToDelete, info, resVar = null)
827
826
async function get ( id , returnType , schema ) {
828
827
let type = returnType ;
829
828
let query = [ aql `FOR i IN` ] ;
830
- if ( graphql . isInterfaceType ( type ) ) {
829
+ if ( graphql . isInterfaceType ( type ) || graphql . isUnionType ( type ) ) {
831
830
let possible_types = schema . getPossibleTypes ( type ) ;
832
831
if ( possible_types . length > 1 ) {
833
832
query . push ( aql `UNION(` ) ;
@@ -866,7 +865,7 @@ async function get(id, returnType, schema) {
866
865
}
867
866
868
867
/**
869
- * Get the source/target an given edge field connected to parent.
868
+ * Get the source/target of a given edge field connected to parent.
870
869
*
871
870
* @param parent
872
871
* @param args
@@ -1058,7 +1057,7 @@ async function getList(args, info) {
1058
1057
const cursor = await db . query ( q ) ;
1059
1058
let result = await cursor . all ( ) ;
1060
1059
let list = {
1061
- '_filter' : queryFilters , // needed to resolve fields 'isEndOfList' and 'totalLength '
1060
+ '_filter' : queryFilters , // needed to resolve fields 'isEndOfList' and 'totalCount '
1062
1061
'content' : result
1063
1062
} ;
1064
1063
return list ;
@@ -1531,13 +1530,12 @@ function getFilters(filterArg, type_to_filter, alias = 'x') {
1531
1530
async function isEndOfList ( parent , args , info ) {
1532
1531
let type = graphql . getNamedType ( info . parentType . getFields ( ) [ 'content' ] . type ) ;
1533
1532
let query = [ aql `FOR x IN FLATTEN(FOR i IN [` ] ;
1534
- addPossibleTypes ( query , info . schema , type ) ;
1533
+ query . push ( getPossibleTypes ( type , info . schema ) ) ; ;
1535
1534
query . push ( aql `] RETURN i)` ) ;
1536
1535
1537
1536
// add filters
1538
- if ( parent . _filter ) {
1539
- query = query . concat ( parent . _filter ) ;
1540
- }
1537
+ query . push ( ...parent . _filter ) ;
1538
+
1541
1539
// get last ID in parent content
1542
1540
if ( parent . content . length != 0 ) {
1543
1541
const last = parent . content [ parent . content . length - 1 ] ;
@@ -1546,6 +1544,7 @@ async function isEndOfList(parent, args, info) {
1546
1544
1547
1545
query . push ( aql `SORT x._id COLLECT WITH COUNT INTO length RETURN length` ) ;
1548
1546
try {
1547
+ console . debug ( aql . join ( query ) ) ;
1549
1548
const cursor = await db . query ( aql . join ( query ) ) ;
1550
1549
const result = await cursor . next ( ) ;
1551
1550
return result == 0 ;
@@ -1567,16 +1566,15 @@ async function isEndOfList(parent, args, info) {
1567
1566
async function getTotalCount ( parent , args , info ) {
1568
1567
let type = graphql . getNamedType ( info . parentType . getFields ( ) [ 'content' ] . type ) ;
1569
1568
let query = [ aql `FOR x IN FLATTEN(FOR i IN [` ] ;
1570
- addPossibleTypes ( query , info . schema , type ) ;
1569
+ query . push ( getPossibleTypes ( type , info . schema ) ) ;
1571
1570
query . push ( aql `] RETURN i)` ) ;
1572
1571
1573
1572
// add filters
1574
- if ( parent . _filter ) {
1575
- query = query . concat ( parent . _filter ) ;
1576
- }
1573
+ query . push ( ...parent . _filter ) ;
1577
1574
1578
1575
query . push ( aql `COLLECT WITH COUNT INTO length RETURN length` ) ;
1579
1576
try {
1577
+ console . debug ( aql . join ( query ) ) ;
1580
1578
const cursor = await db . query ( aql . join ( query ) ) ;
1581
1579
return await cursor . next ( ) ;
1582
1580
} catch ( err ) {
@@ -1621,6 +1619,31 @@ function createParamVar(ctxt) {
1621
1619
return `_${ ctxt . paramVarCounter } ` ;
1622
1620
}
1623
1621
1622
+ /**
1623
+ * Return an AQL query fragment listing all possible collections for the given type.
1624
+ *
1625
+ * If context is not null, collections are explicitly bound to AQL variables.
1626
+ *
1627
+ * @param type
1628
+ * @param schema
1629
+ * @param conext = null (optional)
1630
+ */
1631
+ function getPossibleTypes ( type , schema , ctxt = null ) {
1632
+ let collections = [ ] ;
1633
+ let types = graphql . isUnionType ( type ) || graphql . isInterfaceType ( type ) ? schema . getPossibleTypes ( type ) : [ type ] ;
1634
+
1635
+ for ( let t of types ) {
1636
+ if ( ctxt !== null ) {
1637
+ let collectionVar = asAQLVar ( getCollectionVar ( t . name , ctxt , true ) ) ;
1638
+ collections . push ( collectionVar ) ;
1639
+ } else {
1640
+ let collection = db . collection ( t . name )
1641
+ collections . push ( aql `${ collection } ` ) ;
1642
+ }
1643
+ }
1644
+ return aql . join ( collections , ',' ) ;
1645
+ }
1646
+
1624
1647
/**
1625
1648
* Add all possible collections for the given type to query
1626
1649
* If context is not null, it is assumed it is for a mutation.
0 commit comments