Skip to content

Commit 96e1668

Browse files
committed
Add support for multiple mutation blocks
1 parent 9ebff83 commit 96e1668

5 files changed

Lines changed: 470 additions & 81 deletions

File tree

dgraph/cmd/alpha/upsert_test.go

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2230,3 +2230,328 @@ func TestInvalidAliasUids(t *testing.T) {
22302230
_, err := mutationWithTs(m1, "application/rdf", false, true, 0)
22312231
require.Contains(t, "query alias [uids] not allowed", err.Error())
22322232
}
2233+
2234+
func TestMultipleMutation(t *testing.T) {
2235+
require.NoError(t, dropAll())
2236+
require.NoError(t, alterSchema(`email: string @index(exact) .`))
2237+
2238+
m1 := `
2239+
upsert {
2240+
query {
2241+
q(func: eq(email, "email@company.io")) {
2242+
v as uid
2243+
}
2244+
}
2245+
2246+
mutation @if(not(eq(len(v), 0))) {
2247+
set {
2248+
uid(v) <name> "not_name" .
2249+
uid(v) <email> "not_email@company.io" .
2250+
}
2251+
}
2252+
2253+
mutation @if(eq(len(v), 0)) {
2254+
set {
2255+
_:user <name> "name" .
2256+
_:user <email> "email@company.io" .
2257+
}
2258+
}
2259+
}`
2260+
mr, err := mutationWithTs(m1, "application/rdf", false, true, 0)
2261+
require.NoError(t, err)
2262+
require.True(t, len(mr.keys) == 0)
2263+
require.Equal(t, []string{"1-email", "1-name"}, mr.preds)
2264+
result := QueryResult{}
2265+
require.NoError(t, json.Unmarshal(mr.data, &result))
2266+
require.Equal(t, 0, len(result.Q))
2267+
2268+
q1 := `
2269+
{
2270+
q(func: eq(email, "email@company.io")) {
2271+
name
2272+
}
2273+
}`
2274+
res, _, err := queryWithTs(q1, "application/graphql+-", "", 0)
2275+
expectedRes := `
2276+
{
2277+
"data": {
2278+
"q": [{
2279+
"name": "name"
2280+
}]
2281+
}
2282+
}`
2283+
require.NoError(t, err)
2284+
testutil.CompareJSON(t, res, expectedRes)
2285+
2286+
// This time the other mutation will get executed
2287+
_, err = mutationWithTs(m1, "application/rdf", false, true, 0)
2288+
require.NoError(t, err)
2289+
2290+
q2 := `
2291+
{
2292+
q(func: eq(email, "not_email@company.io")) {
2293+
name
2294+
}
2295+
}`
2296+
res, _, err = queryWithTs(q2, "application/graphql+-", "", 0)
2297+
require.NoError(t, err)
2298+
2299+
expectedRes = `
2300+
{
2301+
"data": {
2302+
"q": [{
2303+
"name": "not_name"
2304+
}]
2305+
}
2306+
}`
2307+
require.NoError(t, err)
2308+
testutil.CompareJSON(t, res, expectedRes)
2309+
}
2310+
2311+
func TestMultiMutationWithoutIf(t *testing.T) {
2312+
require.NoError(t, dropAll())
2313+
require.NoError(t, alterSchema(`email: string @index(exact) .`))
2314+
2315+
m1 := `
2316+
upsert {
2317+
query {
2318+
me(func: eq(email, "email@company.io")) {
2319+
v as uid
2320+
}
2321+
}
2322+
2323+
mutation @if(not(eq(len(v), 0))) {
2324+
set {
2325+
uid(v) <name> "not_name" .
2326+
uid(v) <email> "not_email@company.io" .
2327+
}
2328+
}
2329+
2330+
mutation @if(eq(len(v), 0)) {
2331+
set {
2332+
_:user <name> "name" .
2333+
}
2334+
}
2335+
2336+
mutation {
2337+
set {
2338+
_:user <email> "email@company.io" .
2339+
}
2340+
}
2341+
2342+
mutation {
2343+
set {
2344+
_:other <name> "other" .
2345+
_:other <email> "other@company.io" .
2346+
}
2347+
}
2348+
}`
2349+
mr, err := mutationWithTs(m1, "application/rdf", false, true, 0)
2350+
require.NoError(t, err)
2351+
require.True(t, len(mr.keys) == 0)
2352+
require.Equal(t, []string{"1-email", "1-name"}, mr.preds)
2353+
2354+
q1 := `
2355+
{
2356+
q(func: has(email)) {
2357+
name
2358+
}
2359+
}`
2360+
res, _, err := queryWithTs(q1, "application/graphql+-", "", 0)
2361+
expectedRes := `
2362+
{
2363+
"data": {
2364+
"q": [{
2365+
"name": "name"
2366+
},
2367+
{
2368+
"name": "other"
2369+
}]
2370+
}
2371+
}`
2372+
require.NoError(t, err)
2373+
testutil.CompareJSON(t, res, expectedRes)
2374+
}
2375+
2376+
func TestMultiMutationCount(t *testing.T) {
2377+
require.NoError(t, dropAll())
2378+
require.NoError(t, alterSchema(`
2379+
email: string @index(exact) .
2380+
count: int .`))
2381+
2382+
m1 := `
2383+
upsert {
2384+
query {
2385+
q(func: eq(email, "email@company.io")) {
2386+
v as uid
2387+
c as count
2388+
nc as math(c+1)
2389+
}
2390+
}
2391+
2392+
mutation @if(eq(len(v), 0)) {
2393+
set {
2394+
uid(v) <name> "name" .
2395+
uid(v) <email> "email@company.io" .
2396+
uid(v) <count> "1" .
2397+
}
2398+
}
2399+
2400+
mutation @if(not(eq(len(v), 0))) {
2401+
set {
2402+
uid(v) <count> val(nc) .
2403+
}
2404+
}
2405+
}`
2406+
mr, err := mutationWithTs(m1, "application/rdf", false, true, 0)
2407+
require.NoError(t, err)
2408+
require.True(t, len(mr.keys) == 0)
2409+
require.Equal(t, []string{"1-count", "1-email", "1-name"}, mr.preds)
2410+
2411+
q1 := `
2412+
{
2413+
q(func: has(email)) {
2414+
count
2415+
}
2416+
}`
2417+
res, _, err := queryWithTs(q1, "application/graphql+-", "", 0)
2418+
expectedRes := `
2419+
{
2420+
"data": {
2421+
"q": [{
2422+
"count": 1
2423+
}]
2424+
}
2425+
}`
2426+
require.NoError(t, err)
2427+
testutil.CompareJSON(t, res, expectedRes)
2428+
2429+
// second time
2430+
mr, err = mutationWithTs(m1, "application/rdf", false, true, 0)
2431+
require.NoError(t, err)
2432+
require.True(t, len(mr.keys) == 0)
2433+
require.Equal(t, []string{"1-count"}, mr.preds)
2434+
2435+
res, _, err = queryWithTs(q1, "application/graphql+-", "", 0)
2436+
expectedRes = `
2437+
{
2438+
"data": {
2439+
"q": [{
2440+
"count": 2
2441+
}]
2442+
}
2443+
}`
2444+
require.NoError(t, err)
2445+
testutil.CompareJSON(t, res, expectedRes)
2446+
}
2447+
2448+
func TestMultipleMutationMerge(t *testing.T) {
2449+
require.NoError(t, dropAll())
2450+
require.NoError(t, alterSchema(`
2451+
name: string @index(term) .
2452+
email: [string] @index(exact) @upsert .`))
2453+
2454+
m1 := `
2455+
{
2456+
set {
2457+
_:user1 <name> "user1" .
2458+
_:user1 <email> "user_email1@company1.io" .
2459+
_:user2 <name> "user2" .
2460+
_:user2 <email> "user_email2@company1.io" .
2461+
}
2462+
}`
2463+
mr, err := mutationWithTs(m1, "application/rdf", false, true, 0)
2464+
require.NoError(t, err)
2465+
require.True(t, len(mr.keys) == 0)
2466+
require.Equal(t, []string{"1-email", "1-name"}, mr.preds)
2467+
2468+
q1 := `
2469+
{
2470+
q(func: has(name)) {
2471+
uid
2472+
}
2473+
}`
2474+
res, _, err := queryWithTs(q1, "application/graphql+-", "", 0)
2475+
require.NoError(t, err)
2476+
var result struct {
2477+
Data struct {
2478+
Q []struct {
2479+
UID string `json:"uid"`
2480+
} `json:"q"`
2481+
} `json:"data"`
2482+
}
2483+
require.NoError(t, json.Unmarshal([]byte(res), &result))
2484+
require.Equal(t, 2, len(result.Data.Q))
2485+
2486+
m2 := `
2487+
upsert {
2488+
query {
2489+
# filter is needed to ensure that we do not get same UIDs in u1 and u2
2490+
q1(func: eq(email, "user_email1@company1.io")) @filter(not(eq(email, "user_email2@company1.io"))) {
2491+
u1 as uid
2492+
}
2493+
2494+
q2(func: eq(email, "user_email2@company1.io")) @filter(not(eq(email, "user_email1@company1.io"))) {
2495+
u2 as uid
2496+
}
2497+
2498+
q3(func: eq(email, "user_email1@company1.io")) @filter(eq(email, "user_email2@company1.io")) {
2499+
u3 as uid
2500+
}
2501+
}
2502+
2503+
# case when both emails do not exist
2504+
mutation @if(eq(len(u1), 0) AND eq(len(u2), 0) AND eq(len(u3), 0)) {
2505+
set {
2506+
_:user <name> "user" .
2507+
_:user <email> "user_email1@company1.io" .
2508+
_:user <email> "user_email2@company1.io" .
2509+
}
2510+
}
2511+
2512+
# case when email1 exists but email2 does not
2513+
mutation @if(eq(len(u1), 1) AND eq(len(u2), 0) AND eq(len(u3), 0)) {
2514+
set {
2515+
uid(u1) <email> "user_email2@company1.io" .
2516+
}
2517+
}
2518+
2519+
# case when email1 does not exist but email2 exists
2520+
mutation @if(eq(len(u1), 0) AND eq(len(u2), 1) AND eq(len(u3), 0)) {
2521+
set {
2522+
uid(u2) <email> "user_email1@company1.io" .
2523+
}
2524+
}
2525+
2526+
# case when both emails exist and needs merging
2527+
mutation @if(eq(len(u1), 1) AND eq(len(u2), 1) AND eq(len(u3), 0)) {
2528+
set {
2529+
_:user <name> "user" .
2530+
_:user <email> "user_email1@company1.io" .
2531+
_:user <email> "user_email2@company1.io" .
2532+
}
2533+
2534+
delete {
2535+
uid(u1) <name> * .
2536+
uid(u1) <email> * .
2537+
uid(u2) <name> * .
2538+
uid(u2) <email> * .
2539+
}
2540+
}
2541+
}`
2542+
mr, err = mutationWithTs(m2, "application/rdf", false, true, 0)
2543+
require.NoError(t, err)
2544+
require.True(t, len(mr.keys) == 0)
2545+
require.Equal(t, []string{"1-email", "1-name"}, mr.preds)
2546+
2547+
res, _, err = queryWithTs(q1, "application/graphql+-", "", 0)
2548+
require.NoError(t, err)
2549+
require.NoError(t, json.Unmarshal([]byte(res), &result))
2550+
require.Equal(t, 1, len(result.Data.Q))
2551+
2552+
// Now, data is all correct. So, following mutation should be no-op
2553+
mr, err = mutationWithTs(m2, "application/rdf", false, true, 0)
2554+
require.NoError(t, err)
2555+
require.True(t, len(mr.keys) == 0)
2556+
require.Equal(t, 0, len(mr.preds))
2557+
}

0 commit comments

Comments
 (0)