Skip to content

Commit d849375

Browse files
mangalaman93shivaji-kharse
authored andcommitted
feat(graphql): adds @default directive to graphql (#8017) (#8837)
Co-authored-by: shivaji-dgraph <shivaji@dgraph.io>
1 parent 5de5e82 commit d849375

File tree

69 files changed

+1351
-11
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1351
-11
lines changed

graphql/e2e/schema/apollo_service_response.graphql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ input CustomHTTP {
118118
skipIntrospection: Boolean
119119
}
120120

121+
input DgraphDefault {
122+
value: String
123+
}
124+
121125
type Point {
122126
longitude: Float!
123127
latitude: Float!
@@ -201,6 +205,7 @@ directive @search(by: [String!]) on FIELD_DEFINITION
201205
directive @embedding on FIELD_DEFINITION
202206
directive @dgraph(type: String, pred: String) on OBJECT | INTERFACE | FIELD_DEFINITION
203207
directive @id(interface: Boolean) on FIELD_DEFINITION
208+
directive @default(add: DgraphDefault, update: DgraphDefault) on FIELD_DEFINITION
204209
directive @withSubscription on OBJECT | INTERFACE | FIELD_DEFINITION
205210
directive @secret(field: String!, pred: String) on OBJECT | INTERFACE
206211
directive @remote on OBJECT | INTERFACE | UNION | INPUT_OBJECT | ENUM

graphql/e2e/schema/generatedSchema.graphql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ input CustomHTTP {
9999
skipIntrospection: Boolean
100100
}
101101

102+
input DgraphDefault {
103+
value: String
104+
}
105+
102106
type Point {
103107
longitude: Float!
104108
latitude: Float!
@@ -182,6 +186,7 @@ directive @search(by: [String!]) on FIELD_DEFINITION
182186
directive @embedding on FIELD_DEFINITION
183187
directive @dgraph(type: String, pred: String) on OBJECT | INTERFACE | FIELD_DEFINITION
184188
directive @id(interface: Boolean) on FIELD_DEFINITION
189+
directive @default(add: DgraphDefault, update: DgraphDefault) on FIELD_DEFINITION
185190
directive @withSubscription on OBJECT | INTERFACE | FIELD_DEFINITION
186191
directive @secret(field: String!, pred: String) on OBJECT | INTERFACE
187192
directive @auth(

graphql/resolve/add_mutation_test.yaml

Lines changed: 160 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5499,4 +5499,163 @@
54995499
error2:
55005500
{
55015501
"message": "failed to rewrite mutation payload because field id cannot be empty"
5502-
}
5502+
}
5503+
5504+
-
5505+
name: "Add mutation with @default directive"
5506+
gqlmutation: |
5507+
mutation($input: [AddBookingInput!]!) {
5508+
addBooking(input: $input) {
5509+
booking {
5510+
name
5511+
created
5512+
updated
5513+
}
5514+
}
5515+
}
5516+
gqlvariables: |
5517+
{
5518+
"input": [
5519+
{
5520+
"name": "Holiday to Bermuda"
5521+
}
5522+
]
5523+
}
5524+
explanation: "As booking has @default fields and is being added, these should be set to the default add value"
5525+
dgmutations:
5526+
- setjson: |
5527+
{
5528+
"Booking.created": "2000-01-01T00:00:00.00Z",
5529+
"Booking.active": "false",
5530+
"Booking.count": "1",
5531+
"Booking.hotel": "add",
5532+
"Booking.length": "1.1",
5533+
"Booking.status": "ACTIVE",
5534+
"Booking.name": "Holiday to Bermuda",
5535+
"Booking.updated": "2000-01-01T00:00:00.00Z",
5536+
"dgraph.type": [
5537+
"Booking"
5538+
],
5539+
"uid":"_:Booking_1"
5540+
}
5541+
5542+
-
5543+
name: "Add mutation with @default directive uses provided values"
5544+
gqlmutation: |
5545+
mutation($input: [AddBookingInput!]!) {
5546+
addBooking(input: $input) {
5547+
booking {
5548+
name
5549+
created
5550+
updated
5551+
}
5552+
}
5553+
}
5554+
gqlvariables: |
5555+
{
5556+
"input": [
5557+
{
5558+
"name": "Holiday to Bermuda",
5559+
"created": "2022-10-12T07:20:50.52Z",
5560+
"updated": "2023-10-12T07:20:50.52Z",
5561+
"active": false,
5562+
"length": 12.3,
5563+
"status": "INACTIVE",
5564+
"hotel": "provided"
5565+
}
5566+
]
5567+
}
5568+
explanation: "Fields with @default(add) should use input values if provided (note that count is still using default)"
5569+
dgmutations:
5570+
- setjson: |
5571+
{
5572+
"Booking.name": "Holiday to Bermuda",
5573+
"Booking.created": "2022-10-12T07:20:50.52Z",
5574+
"Booking.updated": "2023-10-12T07:20:50.52Z",
5575+
"Booking.active": false,
5576+
"Booking.count": "1",
5577+
"Booking.hotel": "provided",
5578+
"Booking.length": 12.3,
5579+
"Booking.status": "INACTIVE",
5580+
"dgraph.type": [
5581+
"Booking"
5582+
],
5583+
"uid":"_:Booking_1"
5584+
}
5585+
5586+
-
5587+
name: "Upsert mutation with @default directives where only one of the nodes exists"
5588+
explanation: "Booking1 should only have updated timestamp as it exists, Booking2 should have created and updated timestamps"
5589+
gqlmutation: |
5590+
mutation addBookingXID($input: [AddBookingXIDInput!]!) {
5591+
addBookingXID(input: $input, upsert: true) {
5592+
bookingXID {
5593+
name
5594+
}
5595+
}
5596+
}
5597+
gqlvariables: |
5598+
{ "input":
5599+
[
5600+
{
5601+
"id": "Booking1",
5602+
"name": "Trip to Bermuda"
5603+
},
5604+
{
5605+
"id": "Booking2",
5606+
"name": "Trip to Antigua"
5607+
}
5608+
]
5609+
}
5610+
dgquery: |-
5611+
query {
5612+
BookingXID_1(func: eq(BookingXID.id, "Booking1")) {
5613+
uid
5614+
dgraph.type
5615+
}
5616+
BookingXID_2(func: eq(BookingXID.id, "Booking2")) {
5617+
uid
5618+
dgraph.type
5619+
}
5620+
}
5621+
qnametouid: |-
5622+
{
5623+
"BookingXID_1": "0x11"
5624+
}
5625+
dgquerysec: |-
5626+
query {
5627+
BookingXID_1 as BookingXID_1(func: uid(0x11)) @filter(type(BookingXID)) {
5628+
uid
5629+
}
5630+
}
5631+
dgmutations:
5632+
- setjson: |
5633+
{
5634+
"uid" : "uid(BookingXID_1)",
5635+
"BookingXID.id": "Booking1",
5636+
"BookingXID.name": "Trip to Bermuda",
5637+
"BookingXID.updated": "2000-01-01T00:00:00.00Z",
5638+
"BookingXID.active": "true",
5639+
"BookingXID.count": "2",
5640+
"BookingXID.length": "1.2",
5641+
"BookingXID.status": "INACTIVE",
5642+
"BookingXID.hotel": "update"
5643+
}
5644+
cond: "@if(gt(len(BookingXID_1), 0))"
5645+
- setjson: |
5646+
{
5647+
"uid": "_:BookingXID_2",
5648+
"BookingXID.id": "Booking2",
5649+
"BookingXID.name": "Trip to Antigua",
5650+
"BookingXID.created": "2000-01-01T00:00:00.00Z",
5651+
"BookingXID.updated": "2000-01-01T00:00:00.00Z",
5652+
"BookingXID.active": "false",
5653+
"BookingXID.count": "1",
5654+
"BookingXID.length": "1.1",
5655+
"BookingXID.status": "ACTIVE",
5656+
"BookingXID.hotel": "add",
5657+
"dgraph.type": [
5658+
"BookingXID"
5659+
]
5660+
}
5661+

graphql/resolve/mutation_rewriter.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ import (
3434
)
3535

3636
const (
37-
MutationQueryVar = "x"
38-
MutationQueryVarUID = "uid(x)"
39-
updateMutationCondition = `gt(len(x), 0)`
37+
MutationQueryVar = "x"
38+
MutationQueryVarUID = "uid(x)"
39+
updateMutationCondition = `gt(len(x), 0)`
40+
defaultDirectiveUpdateAct = "update"
41+
defaultDirectiveAddAct = "add"
4042
)
4143

4244
// Enum passed on to rewriteObject function.
@@ -1587,6 +1589,8 @@ func rewriteObject(
15871589
}
15881590
}
15891591

1592+
action := defaultDirectiveUpdateAct
1593+
15901594
// This is not an XID reference. This is also not a UID reference.
15911595
// This is definitely a new node.
15921596
// Create new node
@@ -1635,6 +1639,19 @@ func rewriteObject(
16351639
// "_:Project2" . myUID will store the variable generated to reference this node.
16361640
newObj["dgraph.type"] = dgraphTypes
16371641
newObj["uid"] = myUID
1642+
action = defaultDirectiveAddAct
1643+
}
1644+
1645+
// Now we know whether this is a new node or not, we can set @default(add/update) fields
1646+
for _, field := range typ.Fields() {
1647+
var pred = field.DgraphPredicate()
1648+
if newObj[pred] != nil {
1649+
continue
1650+
}
1651+
var value = field.GetDefaultValue(action)
1652+
if value != nil {
1653+
newObj[pred] = value
1654+
}
16381655
}
16391656

16401657
// Add Inverse Link if necessary

graphql/resolve/schema.graphql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,32 @@ type Student implements People {
175175
taughtBy: [Teacher] @hasInverse(field: "teaches")
176176
}
177177

178+
# For testing default values
179+
type Booking {
180+
id: ID!
181+
name: String!
182+
created: DateTime! @default(add: {value: "$now"})
183+
updated: DateTime! @default(add: {value: "$now"}, update: {value: "$now"})
184+
count: Int! @default(add: {value: "1"}, update: {value: "2"})
185+
length: Float! @default(add: {value: "1.1"}, update: {value: "1.2"})
186+
hotel: String! @default(add: {value: "add"}, update: {value: "update"})
187+
active: Boolean! @default(add: {value: "false"}, update: {value: "true"})
188+
status: Status! @default(add: {value: "ACTIVE"}, update: {value: "INACTIVE"})
189+
}
190+
191+
# For testing default values with upserts
192+
type BookingXID {
193+
id: String! @id
194+
name: String!
195+
created: DateTime! @default(add: {value: "$now"})
196+
updated: DateTime! @default(add: {value: "$now"}, update: {value: "$now"})
197+
count: Int! @default(add: {value: "1"}, update: {value: "2"})
198+
length: Float! @default(add: {value: "1.1"}, update: {value: "1.2"})
199+
hotel: String! @default(add: {value: "add"}, update: {value: "update"})
200+
active: Boolean! @default(add: {value: "false"}, update: {value: "true"})
201+
status: Status! @default(add: {value: "ACTIVE"}, update: {value: "INACTIVE"})
202+
}
203+
178204
type Comment {
179205
id: ID!
180206
author: String!

graphql/resolve/update_mutation_test.yaml

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2331,7 +2331,7 @@
23312331
explaination: "If nested object have inherited @id field which have interface argument set, and that
23322332
field already exist in some other implementing type than we returns error.In below mutation manages
23332333
is of type LibraryMember but node with given refID already exist in some other
2334-
type than LibraryMember"
2334+
type than than LibraryMember"
23352335
gqlmutation: |
23362336
mutation update($patch: UpdateLibraryManagerInput!) {
23372337
updateLibraryManager(input: $patch) {
@@ -2447,3 +2447,88 @@
24472447
"uid": "uid(x)"
24482448
}
24492449
cond: "@if(gt(len(x), 0))"
2450+
2451+
-
2452+
name: "Update with @default directive"
2453+
gqlmutation: |
2454+
mutation updateBooking($patch: UpdateBookingInput!) {
2455+
updateBooking(input: $patch) {
2456+
booking {
2457+
id
2458+
}
2459+
}
2460+
}
2461+
gqlvariables: |
2462+
{ "patch":
2463+
{ "filter": {
2464+
"id": ["0x123", "0x124"]
2465+
},
2466+
"set": {
2467+
"name": "Flight to Antigua"
2468+
}
2469+
}
2470+
}
2471+
explanation: "The update patch should include default values on the fields with the @default(update:) directive"
2472+
dgquerysec: |-
2473+
query {
2474+
x as updateBooking(func: uid(0x123, 0x124)) @filter(type(Booking)) {
2475+
uid
2476+
}
2477+
}
2478+
dgmutations:
2479+
- setjson: |
2480+
{ "uid" : "uid(x)",
2481+
"Booking.name": "Flight to Antigua",
2482+
"Booking.updated": "2000-01-01T00:00:00.00Z",
2483+
"Booking.active": "true",
2484+
"Booking.count": "2",
2485+
"Booking.length": "1.2",
2486+
"Booking.status": "INACTIVE",
2487+
"Booking.hotel": "update"
2488+
}
2489+
cond: "@if(gt(len(x), 0))"
2490+
2491+
-
2492+
name: "Update with @default directive uses provided values"
2493+
gqlmutation: |
2494+
mutation updateBooking($patch: UpdateBookingInput!) {
2495+
updateBooking(input: $patch) {
2496+
booking {
2497+
id
2498+
}
2499+
}
2500+
}
2501+
gqlvariables: |
2502+
{ "patch":
2503+
{ "filter": {
2504+
"id": ["0x123", "0x124"]
2505+
},
2506+
"set": {
2507+
"name": "Flight to Antigua",
2508+
"updated": "2022-10-12T07:20:50.52Z",
2509+
"active": false,
2510+
"length": 12.3,
2511+
"status": "ACTIVE",
2512+
"hotel": "provided"
2513+
}
2514+
}
2515+
}
2516+
explanation: "Fields with @default(update) should use input values if provided (note that count is still using default)"
2517+
dgquerysec: |-
2518+
query {
2519+
x as updateBooking(func: uid(0x123, 0x124)) @filter(type(Booking)) {
2520+
uid
2521+
}
2522+
}
2523+
dgmutations:
2524+
- setjson: |
2525+
{ "uid" : "uid(x)",
2526+
"Booking.name": "Flight to Antigua",
2527+
"Booking.updated": "2022-10-12T07:20:50.52Z",
2528+
"Booking.active": false,
2529+
"Booking.count": "2",
2530+
"Booking.length": 12.3,
2531+
"Booking.status": "ACTIVE",
2532+
"Booking.hotel": "provided"
2533+
}
2534+
cond: "@if(gt(len(x), 0))"

0 commit comments

Comments
 (0)