sourcenetwork / defradb

DefraDB is a Peer-to-Peer Edge Database. It's the core data storage system for the Source Network Ecosystem, built with IPLD, LibP2P, CRDTs, and Semantic open web properties.
461 stars 46 forks source link

Add `@export` directive to link data between fields/operations #3119

Open jsimnz opened 1 month ago

jsimnz commented 1 month ago

Add a @export directive to query fields that dynamically populates a defined variable. This would allow field values from one query/mutation to be used within another. For now, this should be scoped to a single mutation or query block, but we can add suport for multiple/interleaves mutation and query blocks in the future. Discussion

Example

mutation($dogID: String) {
  create_Dog(input: {name: "Fido"}) {
    _docID @export(as: "dogID")
  }
  update_User(docID:"123", input: {dog: $dogID}) {
    name
    dog
  }
}

Here we are defining a variable at the top of the mutation dogID: String which will have the resulting value from the @export directive from the _docID @export(as: "dogID").

Design

We will need to detect the type of the variable (strongly typed) and make sure: 1) The output type of the field with the @export directive matches the variable type 2) If the exported field is contained within a List type (since create_Dog outputs a [Dog] type) then A) The variable can be a single (non list) type but the output result type can only contain a single value. In other words, the @export directive can only be called once B) Otherwise, the variable must be a list type as well.

Rough outline of the implementation (from here) 1) Define a new directive 2) Specify a serial execution dependency order (should this match the provided order of the ops by the user? Or should it be smarter and recognize which ops output data and which ops depend on data?) 3) Add a validation rule to validate that fields with @export directives defined on the query refer to defined variables within the query, and that the field type is a compatible scalar type (or list-scalar type) with the variable type (see point (2 A/B) above) 4) Add a planNode (or update an existing node (eg selectNode)

Note: The value of the @export field should overwrite any existing manually provided variable value

References

islamaliev commented 1 month ago

I didn't thoroughly read the specs, but do we really need to pass $dogID as a variable to the mutation? Feels artificial. Why not to write like this:

mutation {
  create_Dog(input: {name: "Fido"}) {
    _docID @export(as: "dogID")
  }
  update_User(docID:"123", input: {dog: $dogID}) {
    name
    dog
  }
}
fredcarle commented 1 month ago

@islamaliev I believe that variable need to be defined and typed.

jsimnz commented 1 month ago

Fred is correct here, we could in theory support "implicit" variables in addition to explicit ones, so the more sensitive gql clients work, but that somewhat just complicates things