Files
ent/entc/integration/integration_test.go
Hylke Visser 02bae0d652 Remove update validators for immutable fields (#137)
Summary:
This pull request modifies the update builder template so that it no longer generates code to validate immutable fields.

The first commit breaks the integration code by making the `number` field of `Card` immutable (the generated validation code references non-existent fields of `CardUpdate`/`CardUpdateOne`).

The second commit fixes the issue by making the `update/save` template not render validation code for immutable fields.
Pull Request resolved: https://github.com/facebookincubator/ent/pull/137

Differential Revision: D18288633

Pulled By: a8m

fbshipit-source-id: c0361b833a3971f76280d624f16cd7eda2725c1e
2019-11-02 09:05:08 -07:00

869 lines
33 KiB
Go

// Copyright 2019-present Facebook Inc. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package integration
import (
"context"
"encoding/json"
"fmt"
"math"
"net"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
"testing"
"time"
"github.com/facebookincubator/ent/dialect"
"github.com/facebookincubator/ent/entc/integration/ent"
"github.com/facebookincubator/ent/entc/integration/ent/file"
"github.com/facebookincubator/ent/entc/integration/ent/group"
"github.com/facebookincubator/ent/entc/integration/ent/groupinfo"
"github.com/facebookincubator/ent/entc/integration/ent/node"
"github.com/facebookincubator/ent/entc/integration/ent/pet"
"github.com/facebookincubator/ent/entc/integration/ent/user"
"github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
)
func TestSQLite(t *testing.T) {
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
require.NoError(t, err)
defer client.Close()
require.NoError(t, client.Schema.Create(context.Background()))
for _, tt := range tests {
name := runtime.FuncForPC(reflect.ValueOf(tt).Pointer()).Name()
t.Run(name[strings.LastIndex(name, ".")+1:], func(t *testing.T) {
drop(t, client)
tt(t, client)
})
}
}
func TestMySQL(t *testing.T) {
for version, port := range map[string]int{"56": 3306, "57": 3307, "8": 3308} {
addr := net.JoinHostPort("localhost", strconv.Itoa(port))
t.Run(version, func(t *testing.T) {
client, err := ent.Open("mysql", (&mysql.Config{
User: "root", Passwd: "pass", Net: "tcp", Addr: addr,
DBName: "test", ParseTime: true, AllowNativePasswords: true,
}).FormatDSN())
require.NoError(t, err)
defer client.Close()
require.NoError(t, client.Schema.Create(context.Background()))
for _, tt := range tests {
name := runtime.FuncForPC(reflect.ValueOf(tt).Pointer()).Name()
t.Run(name[strings.LastIndex(name, ".")+1:], func(t *testing.T) {
drop(t, client)
tt(t, client)
})
}
})
}
}
func TestPostgres(t *testing.T) {
for version, port := range map[string]int{"10": 5430, "11": 5431, "12": 5432} {
t.Run(version, func(t *testing.T) {
client, err := ent.Open(dialect.Postgres, fmt.Sprintf("host=localhost port=%d user=postgres dbname=test password=pass sslmode=disable", port))
require.NoError(t, err)
defer client.Close()
require.NoError(t, client.Schema.Create(context.Background()))
for _, tt := range tests {
name := runtime.FuncForPC(reflect.ValueOf(tt).Pointer()).Name()
t.Run(name[strings.LastIndex(name, ".")+1:], func(t *testing.T) {
drop(t, client)
tt(t, client)
})
}
})
}
}
func TestGremlin(t *testing.T) {
client, err := ent.Open("gremlin", "http://localhost:8182")
require.NoError(t, err)
defer client.Close()
// run all tests except transaction and index tests.
for _, tt := range tests[2:] {
name := runtime.FuncForPC(reflect.ValueOf(tt).Pointer()).Name()
t.Run(name[strings.LastIndex(name, ".")+1:], func(t *testing.T) {
drop(t, client)
tt(t, client)
})
}
}
// tests for all drivers to run.
var tests = []func(*testing.T, *ent.Client){
Tx,
Indexes,
Types,
Clone,
Sanity,
Paging,
Select,
Delete,
Relation,
Predicate,
AddValues,
ClearFields,
UniqueConstraint,
O2OTwoTypes,
O2OSameType,
O2OSelfRef,
O2MTwoTypes,
O2MSameType,
M2MSelfRef,
M2MSameType,
M2MTwoTypes,
DefaultValue,
ImmutableValue,
Sensitive,
}
func Sanity(t *testing.T, client *ent.Client) {
require := require.New(t)
ctx := context.Background()
usr := client.User.Create().SetName("foo").SetAge(20).SaveX(ctx)
require.Equal("foo", usr.Name)
require.Equal(20, usr.Age)
require.NotEmpty(usr.ID)
client.User.Query().OnlyX(ctx)
client.User.Delete().ExecX(ctx)
require.Empty(client.User.Query().AllX(ctx))
pt := client.Pet.Create().SetName("pedro").SaveX(ctx)
usr = client.User.Create().SetName("foo").SetAge(20).AddPets(pt).SaveX(ctx)
child := client.User.Create().SetName("bar").SetAge(20).AddChildren(usr).SaveX(ctx)
inf := client.GroupInfo.Create().SetDesc("desc").SaveX(ctx)
grp := client.Group.Create().SetName("Github").SetExpire(time.Now()).AddUsers(usr, child).SetInfo(inf).SaveX(ctx)
require.Equal(1, client.Group.Query().CountX(ctx))
require.Zero(client.Group.Query().Where(group.Active(false)).CountX(ctx))
require.Len(grp.QueryUsers().AllX(ctx), 2)
usr.QueryGroups().OnlyX(ctx)
child.QueryGroups().OnlyX(ctx)
usr2 := client.User.Create().SetName("qux").SetAge(20).SetSpouse(usr).SaveX(ctx)
usr2.QuerySpouse().OnlyX(ctx)
usr.QuerySpouse().OnlyX(ctx)
require.Equal(usr.Name, usr.QueryPets().QueryOwner().OnlyX(ctx).Name)
require.Equal(pt.Name, usr.QueryPets().QueryOwner().QueryPets().OnlyX(ctx).Name)
require.Empty(usr.QuerySpouse().QueryPets().AllX(ctx))
require.Equal(pt.Name, usr2.QuerySpouse().QueryPets().OnlyX(ctx).Name)
require.Len(usr.QueryGroups().QueryUsers().AllX(ctx), 2)
require.Len(usr.QueryGroups().QueryUsers().QueryGroups().AllX(ctx), 1, "should be unique by default")
require.Len(usr.QueryGroups().AllX(ctx), 1)
require.Len(client.User.Query().Where(user.HasPets()).AllX(ctx), 1)
require.Len(client.User.Query().Where(user.HasSpouse()).AllX(ctx), 2)
require.Len(client.User.Query().Where(user.Not(user.HasSpouse())).AllX(ctx), 1)
require.Len(client.User.Query().Where(user.HasGroups()).AllX(ctx), 2)
require.Len(client.Group.Query().Where(group.HasUsers()).AllX(ctx), 1)
require.Len(client.Group.Query().Where(group.HasUsersWith(user.Name("foo"))).AllX(ctx), 1)
require.Len(client.User.Query().Where(user.HasGroupsWith(group.NameHasPrefix("G"))).AllX(ctx), 2)
require.Equal(3, client.User.Query().CountX(ctx))
require.Equal(client.Group.Query().Where(group.HasUsersWith(user.Name("foo"))).CountX(ctx), 1)
require.True(client.User.Query().ExistX(ctx))
require.True(client.User.Query().Where(user.HasPetsWith(pet.NameHasPrefix("ped"))).ExistX(ctx))
require.False(client.User.Query().Where(user.HasPetsWith(pet.NameHasPrefix("pan"))).ExistX(ctx))
require.Equal(child.Name, client.User.Query().Order(ent.Asc("name")).FirstX(ctx).Name)
require.Equal(usr2.Name, client.User.Query().Order(ent.Desc("name")).FirstX(ctx).Name)
// update fields.
client.User.Update().Where(user.ID(child.ID)).SetName("Ariel").SaveX(ctx)
client.User.Query().Where(user.Name("Ariel")).OnlyX(ctx)
// update edges.
require.Empty(child.QueryPets().AllX(ctx))
require.NoError(client.Pet.UpdateOne(pt).ClearOwner().Exec(ctx))
client.User.Update().Where(user.ID(child.ID)).AddPets(pt).SaveX(ctx)
require.NotEmpty(child.QueryPets().AllX(ctx))
client.User.Update().Where(user.ID(child.ID)).RemovePets(pt).SaveX(ctx)
require.Empty(child.QueryPets().AllX(ctx))
// remove edges.
client.User.Update().ClearSpouse().SaveX(ctx)
require.Empty(client.User.Query().Where(user.HasSpouse()).AllX(ctx))
client.User.Update().AddFriends(child).RemoveGroups(grp).Where(user.ID(usr.ID)).SaveX(ctx)
require.NotEmpty(child.QueryGroups().AllX(ctx))
require.Empty(usr.QueryGroups().AllX(ctx))
require.Len(child.QueryFriends().AllX(ctx), 1)
require.Len(usr.QueryFriends().AllX(ctx), 1)
// update one vertex.
usr = client.User.UpdateOne(usr).SetName("baz").AddGroups(grp).SaveX(ctx)
require.Equal("baz", usr.Name)
require.NotEmpty(usr.QueryGroups().AllX(ctx))
// grouping.
var v []struct {
Name string `json:"name"`
Age int `json:"age"`
Sum int `json:"sum"`
Count int `json:"count"`
}
client.User.Query().
GroupBy(user.FieldName, user.FieldAge).
Aggregate(ent.Count(), ent.Sum(user.FieldAge)).
ScanX(ctx, &v)
require.NotEmpty(v)
// IN predicates.
ids := client.User.Query().IDsX(ctx)
require.Len(ids, 3)
client.User.Delete().Where(user.IDIn(ids...)).ExecX(ctx)
ids = client.User.Query().IDsX(ctx)
require.Empty(ids)
// nop.
client.User.Delete().Where(user.IDIn(ids...)).ExecX(ctx)
}
func Clone(t *testing.T, client *ent.Client) {
ctx := context.Background()
f1 := client.File.Create().SetName("foo").SetSize(10).SaveX(ctx)
f2 := client.File.Create().SetName("foo").SetSize(20).SaveX(ctx)
base := client.File.Query().Where(file.Name("foo"))
require.Equal(t, f1.Size, base.Clone().Where(file.Size(f1.Size)).OnlyX(ctx).Size)
require.Equal(t, f2.Size, base.Clone().Where(file.Size(f2.Size)).OnlyX(ctx).Size)
// ensure clone emits valid code.
query := client.Pet.Query().Where(pet.Name("unknown")).QueryTeam()
for i := 0; i < 10; i++ {
_, err := query.Clone().Where(user.Name("unknown")).First(ctx)
require.True(t, ent.IsNotFound(err), "should not return syntax error")
}
}
func Paging(t *testing.T, client *ent.Client) {
require := require.New(t)
ctx := context.Background()
for i := 1; i <= 10; i++ {
client.User.Create().SetName(fmt.Sprintf("name-%d", i)).SetAge(i).SaveX(ctx)
}
require.Equal(10, client.User.Query().CountX(ctx))
require.Len(client.User.Query().Offset(5).AllX(ctx), 5)
require.Len(client.User.Query().Offset(6).AllX(ctx), 4)
require.Equal(
[]int{7, 8},
client.User.Query().
Offset(6).
Limit(2).
Order(ent.Asc(user.FieldAge)).
GroupBy(user.FieldAge).
IntsX(ctx),
)
for i := 0; i < 10; i++ {
require.Equal(i+1, client.User.Query().Order(ent.Asc(user.FieldAge)).Offset(i).Limit(1).AllX(ctx)[0].Age)
}
}
func Select(t *testing.T, client *ent.Client) {
ctx := context.Background()
require := require.New(t)
t.Log("select one field")
client.User.Create().SetName("foo").SetAge(30).SaveX(ctx)
names := client.User.
Query().
Select(user.FieldName).
StringsX(ctx)
require.Equal([]string{"foo"}, names)
client.User.Create().SetName("bar").SetAge(30).SaveX(ctx)
t.Log("select one field with ordering")
names = client.User.
Query().
Order(ent.Asc(user.FieldName)).
Select(user.FieldName).
StringsX(ctx)
require.Equal([]string{"bar", "foo"}, names)
names = client.User.
Query().
Order(ent.Desc(user.FieldName)).
Select(user.FieldName).
StringsX(ctx)
require.Equal([]string{"foo", "bar"}, names)
client.User.Create().SetName("baz").SetAge(30).SaveX(ctx)
names = client.User.
Query().
Order(ent.Asc(user.FieldName)).
Select(user.FieldName).
StringsX(ctx)
require.Equal([]string{"bar", "baz", "foo"}, names)
t.Log("select 2 fields")
var v []struct {
Age int `json:"age"`
Name string `json:"name"`
}
client.User.
Query().
Order(ent.Asc(user.FieldName)).
Select(user.FieldAge, user.FieldName).
ScanX(ctx, &v)
require.Equal([]int{30, 30, 30}, []int{v[0].Age, v[1].Age, v[2].Age})
require.Equal([]string{"bar", "baz", "foo"}, []string{v[0].Name, v[1].Name, v[2].Name})
}
func Predicate(t *testing.T, client *ent.Client) {
require := require.New(t)
ctx := context.Background()
f1 := client.File.Create().SetName("1").SetSize(10).SaveX(ctx)
f2 := client.File.Create().SetName("2").SetSize(20).SaveX(ctx)
f3 := client.File.Create().SetName("3").SetSize(30).SaveX(ctx)
f4 := client.File.Create().SetName("4").SetSize(40).SaveX(ctx)
files := client.File.Query().
Where(
file.Or(
file.Name(f1.Name),
file.And(file.Name(f2.Name), file.Size(f2.Size)),
),
).
Order(ent.Asc(file.FieldName)).
AllX(ctx)
require.Equal(f1.Name, files[0].Name)
require.Equal(f2.Name, files[1].Name)
files = client.File.Query().
Where(
file.Or(
file.Name(f4.Name),
file.And(file.Name(f3.Name), file.Size(f3.Size)),
),
).
Order(ent.Asc(file.FieldName)).
AllX(ctx)
require.Equal(f3.Name, files[0].Name)
require.Equal(f4.Name, files[1].Name)
require.Zero(client.File.Query().Where(file.UserNotNil()).CountX(ctx))
require.Equal(4, client.File.Query().Where(file.UserIsNil()).CountX(ctx))
require.Zero(client.File.Query().Where(file.GroupNotNil()).CountX(ctx))
require.Equal(4, client.File.Query().Where(file.GroupIsNil()).CountX(ctx))
f1 = f1.Update().SetUser("a8m").SaveX(ctx)
require.NotNil(f1.User)
require.Equal("a8m", *f1.User)
require.Equal(3, client.File.Query().Where(file.UserIsNil()).CountX(ctx))
require.Equal(f1.Name, client.File.Query().Where(file.UserNotNil()).OnlyX(ctx).Name)
f5 := client.File.Create().SetName("5").SetSize(40).SetUser("mashraki").SaveX(ctx)
require.NotNil(f5.User)
require.Equal("mashraki", *f5.User)
require.Equal(3, client.File.Query().Where(file.UserIsNil()).CountX(ctx))
require.Equal(2, client.File.Query().Where(file.UserNotNil()).CountX(ctx))
require.Equal(5, client.File.Query().Where(file.GroupIsNil()).CountX(ctx))
f4 = f4.Update().SetGroup("fbc").SaveX(ctx)
require.Equal(1, client.File.Query().Where(file.GroupNotNil()).CountX(ctx))
require.Equal(4, client.File.Query().Where(file.GroupIsNil()).CountX(ctx))
require.Equal(
5,
client.File.Query().
Where(
file.Or(
file.GroupIsNil(),
file.And(
file.GroupNotNil(),
file.Name(f4.Name),
),
),
).
CountX(ctx),
)
}
func AddValues(t *testing.T, client *ent.Client) {
require := require.New(t)
ctx := context.Background()
t.Log("add values to fields")
cmt := client.Comment.Create().SetUniqueInt(1).SetUniqueFloat(1).SaveX(ctx)
cmt = cmt.Update().AddUniqueInt(10).SaveX(ctx)
require.Equal(11, cmt.UniqueInt)
require.Equal(11, client.Comment.Query().OnlyX(ctx).UniqueInt, "should be updated in the database")
t.Log("add values to null fields")
cmt = cmt.Update().AddNillableInt(10).SaveX(ctx)
require.Equal(10, *cmt.NillableInt)
cmt1 := client.Comment.Create().SetUniqueInt(1).SetUniqueFloat(10).SaveX(ctx)
err := cmt1.Update().AddUniqueInt(10).Exec(ctx)
require.True(ent.IsConstraintFailure(err))
cmt1 = cmt1.Update().AddUniqueInt(20).AddNillableInt(20).SaveX(ctx)
require.Equal(21, cmt1.UniqueInt)
require.Equal(20, *cmt1.NillableInt)
cmt1 = cmt1.Update().AddUniqueInt(10).AddUniqueInt(-1).SaveX(ctx)
require.Equal(30, cmt1.UniqueInt)
require.Equal(30, client.Comment.GetX(ctx, cmt1.ID).UniqueInt)
}
func Delete(t *testing.T, client *ent.Client) {
require := require.New(t)
ctx := context.Background()
nd := client.Node.Create().SetValue(1e3).SaveX(ctx)
err := client.Node.DeleteOneID(nd.ID).Exec(ctx)
require.NoError(err)
err = client.Node.DeleteOneID(nd.ID).Exec(ctx)
require.True(ent.IsNotFound(err))
for i := 0; i < 5; i++ {
client.Node.Create().SetValue(i).SaveX(ctx)
}
affected, err := client.Node.Delete().Where(node.ValueGT(2)).Exec(ctx)
require.NoError(err)
require.Equal(2, affected)
affected, err = client.Node.Delete().Exec(ctx)
require.NoError(err)
require.Equal(3, affected)
}
func Relation(t *testing.T, client *ent.Client) {
require := require.New(t)
ctx := context.Background()
t.Log("querying group info")
info, err := client.GroupInfo.
Query().
First(ctx)
require.Nil(info)
require.True(ent.IsNotFound(err))
t.Log("creating group info")
info = client.GroupInfo.
Create().
SetDesc("group info").
SaveX(ctx)
t.Logf("group info created: %v", info)
t.Log("creating group")
grp := client.Group.
Create().
SetInfo(info).
SetName("Github").
SetExpire(time.Now().Add(time.Hour)).
SaveX(ctx)
require.NotZero(grp.ID)
require.Equal(grp.MaxUsers, 10)
require.Equal(grp.Name, "Github")
t.Logf("group created: %v", grp)
t.Log("creating user")
usr := client.User.
Create().
SetAge(20).
SetName("a8m").
AddGroups(grp).
SaveX(ctx)
require.NotZero(usr.ID)
require.Equal(usr.Age, 20)
require.Equal(usr.Name, "a8m")
require.Equal(usr.Last, "unknown")
t.Logf("user created: %v", usr)
t.Log("querying assoc edges")
groups := usr.QueryGroups().IDsX(ctx)
require.NotEmpty(groups)
require.Equal(grp.ID, groups[0])
t.Log("querying inverse edge")
users := grp.QueryUsers().IDsX(ctx)
require.NotEmpty(users)
require.Equal(usr.ID, users[0])
t.Log("remove group edge")
client.User.UpdateOne(usr).RemoveGroups(grp).ExecX(ctx)
require.Empty(grp.QueryUsers().AllX(ctx))
require.Empty(usr.QueryGroups().AllX(ctx))
t.Logf("add group edge")
client.User.UpdateOne(usr).AddGroups(grp).ExecX(ctx)
require.NotEmpty(grp.QueryUsers().AllX(ctx))
require.NotEmpty(usr.QueryGroups().AllX(ctx))
t.Log("remove users inverse edge")
client.Group.UpdateOne(grp).RemoveUsers(usr).ExecX(ctx)
require.Empty(grp.QueryUsers().AllX(ctx))
require.Empty(usr.QueryGroups().AllX(ctx))
t.Logf("add group inverse edge")
client.Group.UpdateOne(grp).AddUsers(usr).ExecX(ctx)
require.NotEmpty(grp.QueryUsers().AllX(ctx))
require.NotEmpty(usr.QueryGroups().AllX(ctx))
t.Log("count vertices")
require.Equal(1, client.User.Query().CountX(ctx))
require.Equal(1, client.Group.Query().CountX(ctx))
t.Log("get only vertices")
require.NotNil(client.User.Query().OnlyX(ctx))
require.NotNil(client.Group.Query().OnlyX(ctx))
t.Log("get only ids")
require.NotEmpty(client.User.Query().OnlyXID(ctx))
require.NotEmpty(client.Group.Query().OnlyXID(ctx))
t.Log("query spouse edge")
require.Zero(client.User.Query().Where(user.HasSpouse()).CountX(ctx))
neta := client.User.Create().SetName("neta").SetAge(18).SetSpouse(usr).SaveX(ctx)
require.Equal(2, client.User.Query().Where(user.HasSpouse()).CountX(ctx))
t.Log("check for singular error")
_, err = client.User.Query().Only(ctx)
require.True(ent.IsNotSingular(err))
t.Log("query parent/children edges")
require.False(usr.QueryParent().ExistX(ctx))
require.Empty(usr.QueryChildren().AllX(ctx))
child := client.User.Create().SetName("pedro").SetAge(7).SetParent(usr).SaveX(ctx)
require.Equal(usr.Name, child.QueryParent().OnlyX(ctx).Name)
require.Equal(child.Name, usr.QueryChildren().OnlyX(ctx).Name)
require.False(usr.QueryParent().ExistX(ctx))
t.Log("clear parent edge")
brat := client.User.Create().SetName("brat").SetAge(19).SetParent(usr).SaveX(ctx)
require.Equal(2, usr.QueryChildren().CountX(ctx))
brat = client.User.UpdateOne(brat).ClearParent().SaveX(ctx)
_, err = client.User.UpdateOne(brat).ClearParent().Save(ctx)
require.NoError(err)
require.False(brat.QueryParent().ExistX(ctx))
require.Equal(1, usr.QueryChildren().CountX(ctx))
t.Log("delete child clears edge")
brat = client.User.UpdateOne(brat).SetParent(usr).SaveX(ctx)
require.Equal(2, usr.QueryChildren().CountX(ctx))
client.User.DeleteOne(brat).ExecX(ctx)
require.Equal(1, usr.QueryChildren().CountX(ctx))
client.Group.UpdateOne(grp).AddBlocked(neta).SaveX(ctx)
blocked := usr.QueryGroups().OnlyX(ctx).QueryBlocked().OnlyX(ctx)
t.Log("blocked:", blocked)
t.Log("query users with or condition")
require.Len(client.User.Query().Where(user.Or(user.Name("a8m"), user.Name("neta"))).AllX(ctx), 2)
require.Len(client.User.Query().Where(user.Or(user.Name("a8m"), user.Name("noam"))).AllX(ctx), 1)
require.Zero(client.User.Query().Where(user.Or(user.Name("alex"), user.Name("noam"))).AllX(ctx))
t.Log("query using the in predicate")
require.Len(client.User.Query().Where(user.NameIn("a8m", "neta")).AllX(ctx), 2)
require.Len(client.User.Query().Where(user.NameIn("a8m", "alex")).AllX(ctx), 1)
require.Len(client.User.Query().Where(user.IDIn(neta.ID)).AllX(ctx), 1)
t.Log("query existence")
require.True(client.User.Query().Where(user.Name("a8m")).Exist(ctx))
require.False(client.User.Query().Where(user.Name("alex")).Exist(ctx))
t.Log("query using get")
require.Equal(usr.Name, client.User.GetX(ctx, usr.ID).Name)
uid, err := client.User.Query().Where(user.ID(usr.ID), user.Not(user.Name(usr.Name))).Only(ctx)
require.Error(err)
require.Nil(uid)
t.Log("test validators")
_, err = client.Group.Create().SetInfo(info).SetType("a").SetName("Gituhb").SetExpire(time.Now().Add(time.Hour)).Save(ctx)
require.Error(err, "type validator failed")
_, err = client.Group.Create().SetInfo(info).SetType("pass").SetName("failed").SetExpire(time.Now().Add(time.Hour)).Save(ctx)
require.Error(err, "name validator failed")
_, err = client.Group.Create().SetInfo(info).SetType("pass").SetName("Github20").SetExpire(time.Now().Add(time.Hour)).Save(ctx)
require.Error(err, "name validator failed")
_, err = client.Group.Create().SetInfo(info).SetType("pass").SetName("Github").SetMaxUsers(-1).SetExpire(time.Now().Add(time.Hour)).Save(ctx)
require.Error(err, "max_users validator failed")
_, err = client.Group.Update().SetMaxUsers(-10).Save(ctx)
require.Error(err, "max_users validator failed")
_, err = client.Group.UpdateOne(grp).SetMaxUsers(-10).Save(ctx)
require.Error(err, "max_users validator failed")
t.Log("query using edge-with predicate")
require.Len(usr.QueryGroups().Where(group.HasInfoWith(groupinfo.Desc("group info"))).AllX(ctx), 1)
require.Empty(usr.QueryGroups().Where(group.HasInfoWith(groupinfo.Desc("missing info"))).AllX(ctx))
t.Log("query using edge-with predicate on inverse edges")
require.Len(client.Group.Query().Where(group.Name("Github"), group.HasUsersWith(user.Name("a8m"))).AllX(ctx), 1)
require.Empty(client.Group.Query().Where(group.Name("Github"), group.HasUsersWith(user.Name("alex"))).AllX(ctx))
t.Logf("query path using edge-with predicate")
require.Len(client.GroupInfo.Query().Where(groupinfo.HasGroupsWith(group.HasUsersWith(user.Name("a8m")))).AllX(ctx), 1)
require.Empty(client.GroupInfo.Query().Where(groupinfo.HasGroupsWith(group.HasUsersWith(user.Name("alex")))).AllX(ctx))
require.Len(client.GroupInfo.Query().Where(groupinfo.Or(groupinfo.Desc("group info"), groupinfo.HasGroupsWith(group.HasUsersWith(user.Name("alex"))))).AllX(ctx), 1)
t.Log("query with ordering")
u1 := client.User.Query().Order(ent.Asc(user.FieldName)).FirstXID(ctx)
u2 := client.User.Query().Order(ent.Desc(user.FieldName)).FirstXID(ctx)
require.NotEqual(u1, u2)
u1 = client.User.Query().Order(ent.Asc(user.FieldLast), ent.Asc(user.FieldAge)).FirstXID(ctx)
u2 = client.User.Query().Order(ent.Asc(user.FieldLast), ent.Desc(user.FieldAge)).FirstXID(ctx)
require.NotEqual(u1, u2)
u1 = client.User.Query().Order(ent.Asc(user.FieldName, user.FieldAge)).FirstXID(ctx)
u2 = client.User.Query().Order(ent.Asc(user.FieldName, user.FieldAge)).FirstXID(ctx)
require.Equal(u1, u2)
t.Log("query path")
require.Len(client.Group.Query().QueryUsers().AllX(ctx), 1)
require.Empty(client.Group.Query().Where(group.Name("boring")).QueryUsers().AllX(ctx))
require.Equal(neta.Name, usr.QueryGroups().Where(group.Name("Github")).QueryUsers().QuerySpouse().OnlyX(ctx).Name)
require.Empty(client.GroupInfo.Query().Where(groupinfo.Desc("group info")).QueryGroups().Where(group.Name("boring")).AllX(ctx))
require.Equal(child.Name, client.GroupInfo.Query().Where(groupinfo.Desc("group info")).QueryGroups().Where(group.Name("Github")).QueryUsers().QueryChildren().FirstX(ctx).Name)
t.Log("query using string predicate")
require.Len(client.User.Query().Where(user.NameIn("a8m", "neta", "pedro")).AllX(ctx), 3)
require.Empty(client.User.Query().Where(user.NameNotIn("a8m", "neta", "pedro")).AllX(ctx))
require.Empty(client.User.Query().Where(user.NameIn("alex", "rocket")).AllX(ctx))
require.NotNil(client.User.Query().Where(user.HasParentWith(user.NameIn("a8m", "neta"))).OnlyX(ctx))
require.Len(client.User.Query().Where(user.NameContains("a8")).AllX(ctx), 1)
require.Len(client.User.Query().Where(user.NameHasPrefix("a8")).AllX(ctx), 1)
require.Len(client.User.Query().Where(user.Or(user.NameHasPrefix("a8"), user.NameHasSuffix("eta"))).AllX(ctx), 2)
t.Log("group-by one field")
names, err := client.User.Query().GroupBy(user.FieldName).Strings(ctx)
require.NoError(err)
sort.Strings(names)
require.Equal([]string{"a8m", "neta", "pedro"}, names)
ages, err := client.User.Query().GroupBy(user.FieldAge).Ints(ctx)
require.NoError(err)
require.Len(ages, 3)
t.Log("group-by two fields with aggregation")
client.User.Create().SetName(usr.Name).SetAge(usr.Age).SaveX(ctx)
client.User.Create().SetName(neta.Name).SetAge(neta.Age).SaveX(ctx)
child2 := client.User.Create().SetName(child.Name).SetAge(child.Age + 1).SaveX(ctx)
var v []struct {
Name string `json:"name"`
Age int `json:"age"`
Sum int `json:"sum"`
Count int `json:"count"`
}
client.User.Query().
GroupBy(user.FieldName, user.FieldAge).
Aggregate(ent.Count(), ent.Sum(user.FieldAge)).
ScanX(ctx, &v)
require.Len(v, 4)
sort.Slice(v, func(i, j int) bool {
if v[i].Name != v[j].Name {
return v[i].Name < v[j].Name
}
return v[i].Age < v[j].Age
})
for i, usr := range []*ent.User{usr, neta} {
require.Equal(usr.Name, v[i].Name)
require.Equal(usr.Age, v[i].Age)
require.Equal(usr.Age*2, v[i].Sum)
require.Equal(2, v[i].Count, "should have 2 vertices")
}
v = v[2:]
for i, usr := range []*ent.User{child, child2} {
require.Equal(usr.Name, v[i].Name)
require.Equal(usr.Age, v[i].Age)
require.Equal(usr.Age, v[i].Sum)
require.Equal(1, v[i].Count)
}
t.Log("group by with .as modulator")
var v2 []struct {
Name string `json:"name"`
Total int `json:"total"`
}
client.User.Query().GroupBy(user.FieldName).Aggregate(ent.As(ent.Count(), "total")).ScanX(ctx, &v2)
require.Len(v2, 3)
for i := range v2 {
require.Equal(2, v2[i].Total)
}
}
func ClearFields(t *testing.T, client *ent.Client) {
ctx := context.Background()
img := client.File.Create().SetName("foo").SetSize(100).SetUser("a8m").SetGroup("Github").SaveX(ctx)
t.Log("clear one field")
img = img.Update().ClearUser().SaveX(ctx)
require.Nil(t, img.User)
img = client.File.Query().OnlyX(ctx)
require.Nil(t, img.User)
require.Equal(t, "Github", img.Group)
t.Log("clear many fields")
img = img.Update().ClearUser().ClearGroup().SaveX(ctx)
require.Nil(t, img.User)
img = client.File.Query().OnlyX(ctx)
require.Nil(t, img.User)
require.Empty(t, img.Group)
t.Log("revert previous set")
img = img.Update().SetUser("a8m").ClearUser().SaveX(ctx)
require.Nil(t, img.User)
}
func UniqueConstraint(t *testing.T, client *ent.Client) {
require := require.New(t)
ctx := context.Background()
t.Log("unique constraint violation on 1 field")
foo := client.User.Create().SetAge(1).SetName("foo").SetNickname("baz").SaveX(ctx)
_, err := client.User.Create().SetAge(1).SetName("bar").SetNickname("baz").Save(ctx)
require.True(ent.IsConstraintFailure(err))
bar := client.User.Create().SetAge(1).SetName("bar").SetNickname("bar").SetPhone("1").SaveX(ctx)
t.Log("unique constraint violation on 2 fields")
_, err = client.User.Create().SetAge(1).SetName("baz").SetNickname("bar").SetPhone("1").Save(ctx)
require.True(ent.IsConstraintFailure(err))
_, err = client.User.Create().SetAge(1).SetName("baz").SetNickname("qux").SetPhone("1").Save(ctx)
require.True(ent.IsConstraintFailure(err))
_, err = client.User.Create().SetAge(1).SetName("baz").SetNickname("bar").SetPhone("2").Save(ctx)
require.True(ent.IsConstraintFailure(err))
client.User.Create().SetAge(1).SetName("baz").SetNickname("qux").SetPhone("2").SaveX(ctx)
_, err = client.User.UpdateOne(foo).SetNickname("bar").SetPhone("1").Save(ctx)
require.True(ent.IsConstraintFailure(err))
_, err = client.User.UpdateOne(foo).SetNickname("bar").SetPhone("2").Save(ctx)
require.True(ent.IsConstraintFailure(err))
t.Log("o2o unique constraint on creation")
dan := client.User.Create().SetAge(1).SetName("dan").SetNickname("dan").SetSpouse(foo).SaveX(ctx)
require.Equal(dan.Name, foo.QuerySpouse().OnlyX(ctx).Name)
_, err = client.User.Create().SetAge(1).SetName("b").SetSpouse(foo).Save(ctx)
require.True(ent.IsConstraintFailure(err))
t.Log("o2m/m2o unique constraint on creation")
c1 := client.User.Create().SetAge(1).SetName("c1").SetNickname("c1").SetParent(foo).SaveX(ctx)
c2 := client.User.Create().SetAge(1).SetName("c2").SetNickname("c2").SetParent(foo).SaveX(ctx)
_, err = client.User.Create().SetAge(10).SetName("z").SetNickname("z").AddChildren(c1).Save(ctx)
require.True(ent.IsConstraintFailure(err), "c1 already has a parent")
_, err = client.User.Create().SetAge(10).SetName("z").SetNickname("z").AddChildren(c2).Save(ctx)
require.True(ent.IsConstraintFailure(err), "c2 already has a parent")
_, err = client.User.Create().SetAge(10).SetName("z").SetNickname("z").AddChildren(c1, c2).Save(ctx)
require.True(ent.IsConstraintFailure(err))
inf := client.GroupInfo.Create().SetDesc("desc").SaveX(ctx)
grp := client.Group.Create().SetName("Github").SetExpire(time.Now()).SetInfo(inf).SaveX(ctx)
_, err = client.GroupInfo.Create().SetDesc("desc").AddGroups(grp).Save(ctx)
require.True(ent.IsConstraintFailure(err))
p1 := client.Pet.Create().SetName("p1").SetOwner(foo).SaveX(ctx)
p2 := client.Pet.Create().SetName("p2").SetOwner(foo).SaveX(ctx)
_, err = client.User.Create().SetAge(10).SetName("new-owner").AddPets(p1, p2).Save(ctx)
require.True(ent.IsConstraintFailure(err))
err = client.User.UpdateOne(c2).SetNickname(c1.Nickname).Exec(ctx)
require.True(ent.IsConstraintFailure(err))
t.Log("o2o unique constraint on update")
err = client.User.UpdateOne(bar).SetSpouse(foo).Exec(ctx)
require.True(ent.IsConstraintFailure(err))
err = client.User.UpdateOne(foo).SetSpouse(bar).Exec(ctx)
require.True(ent.IsConstraintFailure(err))
client.User.UpdateOne(bar).ClearSpouse().ExecX(ctx)
client.User.UpdateOne(foo).ClearSpouse().SetSpouse(bar).ExecX(ctx)
require.False(dan.QuerySpouse().ExistX(ctx))
require.Equal(bar.Name, foo.QuerySpouse().OnlyX(ctx).Name)
require.Equal(foo.Name, bar.QuerySpouse().OnlyX(ctx).Name)
t.Log("o2m unique constraint on update")
_, err = client.User.UpdateOne(bar).SetAge(1).SetName("new-owner").AddPets(p1).Save(ctx)
require.True(ent.IsConstraintFailure(err))
_, err = client.User.UpdateOne(bar).SetAge(1).SetName("new-owner").AddPets(p1, p2).Save(ctx)
require.True(ent.IsConstraintFailure(err))
t.Log("unique constraint violation when updating more than 1 vertex")
err = client.User.Update().SetNickname("yada").Exec(ctx)
require.True(ent.IsConstraintFailure(err))
require.False(client.User.Query().Where(user.Nickname("yada")).ExistX(ctx))
client.User.Update().Where(user.Nickname("dan")).SetNickname("yada").ExecX(ctx)
require.False(client.User.Query().Where(user.Nickname("dan")).ExistX(ctx))
require.True(client.User.Query().Where(user.Nickname("yada")).ExistX(ctx))
t.Log("unique constraint on numeric fields")
cm1 := client.Comment.Create().SetUniqueInt(42).SetUniqueFloat(math.Pi).SaveX(ctx)
_, err = client.Comment.Create().SetUniqueInt(42).SetUniqueFloat(math.E).Save(ctx)
require.Error(err)
_, err = client.Comment.Create().SetUniqueInt(7).SetUniqueFloat(math.Pi).Save(ctx)
require.Error(err)
_ = client.Comment.Create().SetUniqueInt(7).SetUniqueFloat(math.E).SaveX(ctx)
err = cm1.Update().SetUniqueInt(7).Exec(ctx)
require.Error(err)
err = cm1.Update().SetUniqueFloat(math.E).Exec(ctx)
require.Error(err)
}
func Tx(t *testing.T, client *ent.Client) {
ctx := context.Background()
require := require.New(t)
tx, err := client.Tx(ctx)
require.NoError(err)
tx.Node.Create().SaveX(ctx)
require.NoError(tx.Rollback())
require.Zero(client.Node.Query().CountX(ctx), "rollback should discard all changes")
tx, err = client.Tx(ctx)
require.NoError(err)
nde := tx.Node.Create().SaveX(ctx)
require.NoError(tx.Commit())
require.Error(tx.Commit(), "should return an error on the second call")
require.NotZero(client.Node.Query().CountX(ctx), "commit should save all changes")
_, err = nde.QueryNext().Count(ctx)
require.Error(err, "should not be able to query after tx was closed")
require.Zero(nde.Unwrap().QueryNext().CountX(ctx), "should be able to query the entity after wrap")
tx, err = client.Tx(ctx)
require.NoError(err)
_, err = tx.Client().Tx(ctx)
require.Error(err, "cannot start a transaction within a transaction")
require.NoError(tx.Rollback())
}
func DefaultValue(t *testing.T, client *ent.Client) {
ctx := context.Background()
c1 := client.Card.Create().SetNumber("102030").SetName("Firstname Lastname").SaveX(ctx)
ctime, mtime := c1.CreateTime, c1.UpdateTime
require.False(t, ctime.IsZero())
require.False(t, mtime.IsZero())
c1 = c1.Update().SetName("F Lastname").SaveX(ctx)
require.False(t, c1.CreateTime.IsZero())
require.False(t, c1.UpdateTime.IsZero())
require.False(t, mtime.Equal(c1.UpdateTime))
}
func ImmutableValue(t *testing.T, client *ent.Client) {
tests := []struct {
name string
updater func() interface{}
}{
{
name: "Update",
updater: func() interface{} {
return client.Card.Update()
},
},
{
name: "UpdateOne",
updater: func() interface{} {
return client.Card.Create().SetNumber("42").SaveX(context.Background()).Update()
},
},
}
for _, tc := range tests {
v := reflect.ValueOf(tc.updater())
require.False(t, v.MethodByName("SetCreatedAt").IsValid())
require.False(t, v.MethodByName("SetNillableCreatedAt").IsValid())
require.False(t, v.MethodByName("SetNumber").IsValid())
require.True(t, v.MethodByName("SetName").IsValid())
}
}
func Sensitive(t *testing.T, client *ent.Client) {
require := require.New(t)
ctx := context.Background()
usr := client.User.Create().SetName("foo").SetAge(20).SetPassword("secret-password").SaveX(ctx)
require.Equal("secret-password", usr.Password)
require.Contains(usr.String(), "password=<sensitive>")
b, err := json.Marshal(usr)
require.NoError(err)
require.NotContains(string(b), "secret-password")
}
func drop(t *testing.T, client *ent.Client) {
t.Log("drop data from database")
ctx := context.Background()
client.Pet.Delete().ExecX(ctx)
client.File.Delete().ExecX(ctx)
client.Card.Delete().ExecX(ctx)
client.Node.Delete().ExecX(ctx)
client.User.Delete().ExecX(ctx)
client.Group.Delete().ExecX(ctx)
client.Comment.Delete().ExecX(ctx)
client.GroupInfo.Delete().ExecX(ctx)
client.FieldType.Delete().ExecX(ctx)
client.FileType.Delete().ExecX(ctx)
}