Skip to content

Commit

Permalink
feat(graphql): adds @default directive to graphql (#8017) (#8837)
Browse files Browse the repository at this point in the history
Co-authored-by: shivaji-dgraph <shivaji@dgraph.io>
  • Loading branch information
mangalaman93 and shivaji-kharse authored Aug 27, 2024
1 parent 05bfcae commit e649059
Show file tree
Hide file tree
Showing 69 changed files with 1,351 additions and 11 deletions.
5 changes: 5 additions & 0 deletions graphql/e2e/schema/apollo_service_response.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ input CustomHTTP {
skipIntrospection: Boolean
}

input DgraphDefault {
value: String
}

type Point {
longitude: Float!
latitude: Float!
Expand Down Expand Up @@ -201,6 +205,7 @@ directive @search(by: [String!]) on FIELD_DEFINITION
directive @embedding on FIELD_DEFINITION
directive @dgraph(type: String, pred: String) on OBJECT | INTERFACE | FIELD_DEFINITION
directive @id(interface: Boolean) on FIELD_DEFINITION
directive @default(add: DgraphDefault, update: DgraphDefault) on FIELD_DEFINITION
directive @withSubscription on OBJECT | INTERFACE | FIELD_DEFINITION
directive @secret(field: String!, pred: String) on OBJECT | INTERFACE
directive @remote on OBJECT | INTERFACE | UNION | INPUT_OBJECT | ENUM
Expand Down
5 changes: 5 additions & 0 deletions graphql/e2e/schema/generatedSchema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ input CustomHTTP {
skipIntrospection: Boolean
}

input DgraphDefault {
value: String
}

type Point {
longitude: Float!
latitude: Float!
Expand Down Expand Up @@ -182,6 +186,7 @@ directive @search(by: [String!]) on FIELD_DEFINITION
directive @embedding on FIELD_DEFINITION
directive @dgraph(type: String, pred: String) on OBJECT | INTERFACE | FIELD_DEFINITION
directive @id(interface: Boolean) on FIELD_DEFINITION
directive @default(add: DgraphDefault, update: DgraphDefault) on FIELD_DEFINITION
directive @withSubscription on OBJECT | INTERFACE | FIELD_DEFINITION
directive @secret(field: String!, pred: String) on OBJECT | INTERFACE
directive @auth(
Expand Down
161 changes: 160 additions & 1 deletion graphql/resolve/add_mutation_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5499,4 +5499,163 @@
error2:
{
"message": "failed to rewrite mutation payload because field id cannot be empty"
}
}

-
name: "Add mutation with @default directive"
gqlmutation: |
mutation($input: [AddBookingInput!]!) {
addBooking(input: $input) {
booking {
name
created
updated
}
}
}
gqlvariables: |
{
"input": [
{
"name": "Holiday to Bermuda"
}
]
}
explanation: "As booking has @default fields and is being added, these should be set to the default add value"
dgmutations:
- setjson: |
{
"Booking.created": "2000-01-01T00:00:00.00Z",
"Booking.active": "false",
"Booking.count": "1",
"Booking.hotel": "add",
"Booking.length": "1.1",
"Booking.status": "ACTIVE",
"Booking.name": "Holiday to Bermuda",
"Booking.updated": "2000-01-01T00:00:00.00Z",
"dgraph.type": [
"Booking"
],
"uid":"_:Booking_1"
}
-
name: "Add mutation with @default directive uses provided values"
gqlmutation: |
mutation($input: [AddBookingInput!]!) {
addBooking(input: $input) {
booking {
name
created
updated
}
}
}
gqlvariables: |
{
"input": [
{
"name": "Holiday to Bermuda",
"created": "2022-10-12T07:20:50.52Z",
"updated": "2023-10-12T07:20:50.52Z",
"active": false,
"length": 12.3,
"status": "INACTIVE",
"hotel": "provided"
}
]
}
explanation: "Fields with @default(add) should use input values if provided (note that count is still using default)"
dgmutations:
- setjson: |
{
"Booking.name": "Holiday to Bermuda",
"Booking.created": "2022-10-12T07:20:50.52Z",
"Booking.updated": "2023-10-12T07:20:50.52Z",
"Booking.active": false,
"Booking.count": "1",
"Booking.hotel": "provided",
"Booking.length": 12.3,
"Booking.status": "INACTIVE",
"dgraph.type": [
"Booking"
],
"uid":"_:Booking_1"
}
-
name: "Upsert mutation with @default directives where only one of the nodes exists"
explanation: "Booking1 should only have updated timestamp as it exists, Booking2 should have created and updated timestamps"
gqlmutation: |
mutation addBookingXID($input: [AddBookingXIDInput!]!) {
addBookingXID(input: $input, upsert: true) {
bookingXID {
name
}
}
}
gqlvariables: |
{ "input":
[
{
"id": "Booking1",
"name": "Trip to Bermuda"
},
{
"id": "Booking2",
"name": "Trip to Antigua"
}
]
}
dgquery: |-
query {
BookingXID_1(func: eq(BookingXID.id, "Booking1")) {
uid
dgraph.type
}
BookingXID_2(func: eq(BookingXID.id, "Booking2")) {
uid
dgraph.type
}
}
qnametouid: |-
{
"BookingXID_1": "0x11"
}
dgquerysec: |-
query {
BookingXID_1 as BookingXID_1(func: uid(0x11)) @filter(type(BookingXID)) {
uid
}
}
dgmutations:
- setjson: |
{
"uid" : "uid(BookingXID_1)",
"BookingXID.id": "Booking1",
"BookingXID.name": "Trip to Bermuda",
"BookingXID.updated": "2000-01-01T00:00:00.00Z",
"BookingXID.active": "true",
"BookingXID.count": "2",
"BookingXID.length": "1.2",
"BookingXID.status": "INACTIVE",
"BookingXID.hotel": "update"
}
cond: "@if(gt(len(BookingXID_1), 0))"
- setjson: |
{
"uid": "_:BookingXID_2",
"BookingXID.id": "Booking2",
"BookingXID.name": "Trip to Antigua",
"BookingXID.created": "2000-01-01T00:00:00.00Z",
"BookingXID.updated": "2000-01-01T00:00:00.00Z",
"BookingXID.active": "false",
"BookingXID.count": "1",
"BookingXID.length": "1.1",
"BookingXID.status": "ACTIVE",
"BookingXID.hotel": "add",
"dgraph.type": [
"BookingXID"
]
}
23 changes: 20 additions & 3 deletions graphql/resolve/mutation_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ import (
)

const (
MutationQueryVar = "x"
MutationQueryVarUID = "uid(x)"
updateMutationCondition = `gt(len(x), 0)`
MutationQueryVar = "x"
MutationQueryVarUID = "uid(x)"
updateMutationCondition = `gt(len(x), 0)`
defaultDirectiveUpdateAct = "update"
defaultDirectiveAddAct = "add"
)

// Enum passed on to rewriteObject function.
Expand Down Expand Up @@ -1587,6 +1589,8 @@ func rewriteObject(
}
}

action := defaultDirectiveUpdateAct

// This is not an XID reference. This is also not a UID reference.
// This is definitely a new node.
// Create new node
Expand Down Expand Up @@ -1635,6 +1639,19 @@ func rewriteObject(
// "_:Project2" . myUID will store the variable generated to reference this node.
newObj["dgraph.type"] = dgraphTypes
newObj["uid"] = myUID
action = defaultDirectiveAddAct
}

// Now we know whether this is a new node or not, we can set @default(add/update) fields
for _, field := range typ.Fields() {
var pred = field.DgraphPredicate()
if newObj[pred] != nil {
continue
}
var value = field.GetDefaultValue(action)
if value != nil {
newObj[pred] = value
}
}

// Add Inverse Link if necessary
Expand Down
26 changes: 26 additions & 0 deletions graphql/resolve/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,32 @@ type Student implements People {
taughtBy: [Teacher] @hasInverse(field: "teaches")
}

# For testing default values
type Booking {
id: ID!
name: String!
created: DateTime! @default(add: {value: "$now"})
updated: DateTime! @default(add: {value: "$now"}, update: {value: "$now"})
count: Int! @default(add: {value: "1"}, update: {value: "2"})
length: Float! @default(add: {value: "1.1"}, update: {value: "1.2"})
hotel: String! @default(add: {value: "add"}, update: {value: "update"})
active: Boolean! @default(add: {value: "false"}, update: {value: "true"})
status: Status! @default(add: {value: "ACTIVE"}, update: {value: "INACTIVE"})
}

# For testing default values with upserts
type BookingXID {
id: String! @id
name: String!
created: DateTime! @default(add: {value: "$now"})
updated: DateTime! @default(add: {value: "$now"}, update: {value: "$now"})
count: Int! @default(add: {value: "1"}, update: {value: "2"})
length: Float! @default(add: {value: "1.1"}, update: {value: "1.2"})
hotel: String! @default(add: {value: "add"}, update: {value: "update"})
active: Boolean! @default(add: {value: "false"}, update: {value: "true"})
status: Status! @default(add: {value: "ACTIVE"}, update: {value: "INACTIVE"})
}

type Comment {
id: ID!
author: String!
Expand Down
87 changes: 86 additions & 1 deletion graphql/resolve/update_mutation_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2331,7 +2331,7 @@
explaination: "If nested object have inherited @id field which have interface argument set, and that
field already exist in some other implementing type than we returns error.In below mutation manages
is of type LibraryMember but node with given refID already exist in some other
type than LibraryMember"
type than than LibraryMember"
gqlmutation: |
mutation update($patch: UpdateLibraryManagerInput!) {
updateLibraryManager(input: $patch) {
Expand Down Expand Up @@ -2447,3 +2447,88 @@
"uid": "uid(x)"
}
cond: "@if(gt(len(x), 0))"
-
name: "Update with @default directive"
gqlmutation: |
mutation updateBooking($patch: UpdateBookingInput!) {
updateBooking(input: $patch) {
booking {
id
}
}
}
gqlvariables: |
{ "patch":
{ "filter": {
"id": ["0x123", "0x124"]
},
"set": {
"name": "Flight to Antigua"
}
}
}
explanation: "The update patch should include default values on the fields with the @default(update:) directive"
dgquerysec: |-
query {
x as updateBooking(func: uid(0x123, 0x124)) @filter(type(Booking)) {
uid
}
}
dgmutations:
- setjson: |
{ "uid" : "uid(x)",
"Booking.name": "Flight to Antigua",
"Booking.updated": "2000-01-01T00:00:00.00Z",
"Booking.active": "true",
"Booking.count": "2",
"Booking.length": "1.2",
"Booking.status": "INACTIVE",
"Booking.hotel": "update"
}
cond: "@if(gt(len(x), 0))"
-
name: "Update with @default directive uses provided values"
gqlmutation: |
mutation updateBooking($patch: UpdateBookingInput!) {
updateBooking(input: $patch) {
booking {
id
}
}
}
gqlvariables: |
{ "patch":
{ "filter": {
"id": ["0x123", "0x124"]
},
"set": {
"name": "Flight to Antigua",
"updated": "2022-10-12T07:20:50.52Z",
"active": false,
"length": 12.3,
"status": "ACTIVE",
"hotel": "provided"
}
}
}
explanation: "Fields with @default(update) should use input values if provided (note that count is still using default)"
dgquerysec: |-
query {
x as updateBooking(func: uid(0x123, 0x124)) @filter(type(Booking)) {
uid
}
}
dgmutations:
- setjson: |
{ "uid" : "uid(x)",
"Booking.name": "Flight to Antigua",
"Booking.updated": "2022-10-12T07:20:50.52Z",
"Booking.active": false,
"Booking.count": "2",
"Booking.length": 12.3,
"Booking.status": "ACTIVE",
"Booking.hotel": "provided"
}
cond: "@if(gt(len(x), 0))"
Loading

0 comments on commit e649059

Please sign in to comment.