v4 without errors

This commit is contained in:
adlerhurst
2025-04-30 09:30:48 +02:00
parent 597781b389
commit 050aa7dd48
11 changed files with 314 additions and 130 deletions

View File

@@ -15,7 +15,7 @@ var (
userCodeAlgorithm crypto.EncryptionAlgorithm
tracer tracing.Tracer
// userRepo func(database.QueryExecutor) UserRepository
userRepo func(database.QueryExecutor) UserRepository
instanceRepo func(database.QueryExecutor) InstanceRepository
cryptoRepo func(database.QueryExecutor) CryptoRepository
orgRepo func(database.QueryExecutor) OrgRepository
@@ -39,9 +39,9 @@ func SetTracer(t tracing.Tracer) {
tracer = t
}
// func SetUserRepository(repo func(database.QueryExecutor) UserRepository) {
// userRepo = repo
// }
func SetUserRepository(repo func(database.QueryExecutor) UserRepository) {
userRepo = repo
}
func SetInstanceRepository(repo func(database.QueryExecutor) InstanceRepository) {
instanceRepo = repo

View File

@@ -2,8 +2,7 @@ package domain
import (
"context"
v4 "github.com/zitadel/zitadel/backend/v3/storage/database/repository/stmt/v4"
"time"
)
type EmailVerifiedCommand struct {
@@ -27,7 +26,8 @@ var (
// Execute implements [Commander]
func (cmd *EmailVerifiedCommand) Execute(ctx context.Context, opts *CommandOpts) error {
return userRepo(opts.DB).Human().ByID(cmd.UserID).Exec().SetEmailVerified(ctx, cmd.Email.Address)
repo := userRepo(opts.DB).Human()
return repo.Update(ctx, repo.IDCondition(cmd.UserID), repo.SetEmailVerifiedAt(time.Time{}))
}
// applyOnSetEmail implements [SetEmailOpt]
@@ -78,8 +78,9 @@ func (cmd *SendCodeCommand) ensureEmail(ctx context.Context, opts *CommandOpts)
if cmd.Email != "" {
return nil
}
email, err := userRepo(opts.DB).Human().ByID(cmd.UserID).Exec().GetEmail(ctx)
if err != nil || email.IsVerified {
repo := userRepo(opts.DB).Human()
email, err := repo.GetEmail(ctx, repo.IDCondition(cmd.UserID))
if err != nil || !email.VerifiedAt.IsZero() {
return err
}
cmd.Email = email.Address
@@ -137,10 +138,9 @@ func (cmd *ReturnCodeCommand) ensureEmail(ctx context.Context, opts *CommandOpts
if cmd.Email != "" {
return nil
}
user := v4.UserRepository(opts.DB)
user.WithCondition(user.IDCondition(cmd.UserID))
email, err := user.he.GetEmail(ctx)
if err != nil || email.IsVerified {
repo := userRepo(opts.DB).Human()
email, err := repo.GetEmail(ctx, repo.IDCondition(cmd.UserID))
if err != nil || !email.VerifiedAt.IsZero() {
return err
}
cmd.Email = email.Address

View File

@@ -38,7 +38,8 @@ func (cmd *SetEmailCommand) Execute(ctx context.Context, opts *CommandOpts) erro
}
defer func() { err = close(ctx, err) }()
// userStatement(opts.DB).Human().ByID(cmd.UserID).SetEmail(ctx, cmd.Email)
err = userRepo(opts.DB).Human().ByID(cmd.UserID).Exec().SetEmail(ctx, cmd.Email)
repo := userRepo(opts.DB).Human()
err = repo.Update(ctx, repo.IDCondition(cmd.UserID), repo.SetEmailAddress(cmd.Email))
if err != nil {
return err
}
@@ -59,6 +60,6 @@ func (cmd *SetEmailCommand) Events() []*eventstore.Event {
}
// applyOnCreateHuman implements [CreateHumanOpt].
func (cmd *SetEmailCommand) applyOnCreateHuman(createUserCmd *CreateUserCommand[Human]) {
func (cmd *SetEmailCommand) applyOnCreateHuman(createUserCmd *CreateUserCommand) {
createUserCmd.email = cmd
}

View File

@@ -9,13 +9,13 @@ import (
type userColumns interface {
// TODO: move v4.columns to domain
InstanceIDColumn() column
OrgIDColumn() column
IDColumn() column
usernameColumn() column
CreatedAtColumn() column
UpdatedAtColumn() column
DeletedAtColumn() column
InstanceIDColumn() v4.Column
OrgIDColumn() v4.Column
IDColumn() v4.Column
usernameColumn() v4.Column
CreatedAtColumn() v4.Column
UpdatedAtColumn() v4.Column
DeletedAtColumn() v4.Column
}
type userConditions interface {
@@ -29,30 +29,35 @@ type userConditions interface {
DeletedAtCondition(op v4.NumberOperator, deletedAt time.Time) v4.Condition
}
type userChanges interface {
SetUsername(username string) v4.Change
}
type UserRepository interface {
userColumns
userConditions
userChanges
// TODO: move condition to domain
WithCondition(condition v4.Condition) UserRepository
Get(ctx context.Context) (*User, error)
List(ctx context.Context) ([]*User, error)
Create(ctx context.Context, user *User) error
Delete(ctx context.Context) error
Get(ctx context.Context, opts v4.QueryOption) (*User, error)
List(ctx context.Context, opts v4.QueryOption) ([]*User, error)
Delete(ctx context.Context, condition v4.Condition) error
Human() HumanRepository
Machine() MachineRepository
}
type humanColumns interface {
FirstNameColumn() column
LastNameColumn() column
EmailAddressColumn() column
EmailVerifiedAtColumn() column
PhoneNumberColumn() column
PhoneVerifiedAtColumn() column
userColumns
FirstNameColumn() v4.Column
LastNameColumn() v4.Column
EmailAddressColumn() v4.Column
EmailVerifiedAtColumn() v4.Column
PhoneNumberColumn() v4.Column
PhoneVerifiedAtColumn() v4.Column
}
type humanConditions interface {
userConditions
FirstNameCondition(op v4.TextOperator, firstName string) v4.Condition
LastNameCondition(op v4.TextOperator, lastName string) v4.Condition
EmailAddressCondition(op v4.TextOperator, email string) v4.Condition
@@ -63,26 +68,53 @@ type humanConditions interface {
PhoneVerifiedAtCondition(op v4.TextOperator, phoneVerifiedAt string) v4.Condition
}
type humanChanges interface {
userChanges
SetFirstName(firstName string) v4.Change
SetLastName(lastName string) v4.Change
SetEmail(address string, verified *time.Time) v4.Change
SetEmailAddress(email string) v4.Change
SetEmailVerifiedAt(emailVerifiedAt time.Time) v4.Change
SetPhone(number string, verifiedAt *time.Time) v4.Change
SetPhoneNumber(phoneNumber string) v4.Change
SetPhoneVerifiedAt(phoneVerifiedAt time.Time) v4.Change
}
type HumanRepository interface {
humanColumns
humanConditions
humanChanges
GetEmail(ctx context.Context) (*Email, error)
GetEmail(ctx context.Context, condition v4.Condition) (*Email, error)
// TODO: replace any with add email update columns
SetEmail(ctx context.Context, columns ...any) error
Create(ctx context.Context, user *User) error
Update(ctx context.Context, condition v4.Condition, changes ...v4.Change) error
}
type machineColumns interface {
DescriptionColumn() column
userColumns
DescriptionColumn() v4.Column
}
type machineConditions interface {
userConditions
DescriptionCondition(op v4.TextOperator, description string) v4.Condition
}
type machineChanges interface {
userChanges
SetDescription(description string) v4.Change
}
type MachineRepository interface {
machineColumns
machineConditions
machineChanges
Create(ctx context.Context, user *User) error
Update(ctx context.Context, condition v4.Condition, changes ...v4.Change) error
}
// type UserRepository interface {
@@ -171,6 +203,11 @@ type User struct {
v4.User
}
type Email struct {
v4.Email
IsVerified bool
}
// type userTraits interface {
// isUserTraits()
// }

View File

@@ -50,6 +50,17 @@ var _ Change = Changes(nil)
var _ Change = (*change[string])(nil)
type Columns []Column
func (m Columns) writeTo(builder *statementBuilder) {
for i, col := range m {
if i > 0 {
builder.WriteString(", ")
}
col.writeTo(builder)
}
}
type Column interface {
writeTo(builder *statementBuilder)
}

View File

@@ -59,6 +59,8 @@ CREATE TABLE users (
-- , CONSTRAINT fk_instances FOREIGN KEY (instance_id) REFERENCES instances(id)
) INHERITS (org_objects);
CREATE INDEX idx_users_username ON users(username);
CREATE TRIGGER set_updated_at
BEFORE UPDATE
ON users
@@ -74,6 +76,8 @@ CREATE TABLE human_users(
, CONSTRAINT fk_instances FOREIGN KEY (instance_id) REFERENCES instances(id)
) INHERITS (users);
CREATE INDEX idx_human_users_username ON human_users(username);
CREATE TRIGGER set_updated_at
BEFORE UPDATE
ON human_users
@@ -88,23 +92,15 @@ CREATE TABLE machine_users(
, CONSTRAINT fk_instances FOREIGN KEY (instance_id) REFERENCES instances(id)
) INHERITS (users);
CREATE INDEX idx_machine_users_username ON machine_users(username);
CREATE TRIGGER set_updated_at
BEFORE UPDATE
ON machine_users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
select u.*, hu.first_name, hu.last_name, mu.description from users u
left join human_users hu on u.instance_id = hu.instance_id and u.org_id = hu.org_id and u.id = hu.id
left join machine_users mu on u.instance_id = mu.instance_id and u.org_id = mu.org_id and u.id = mu.id
-- where
-- u.instance_id = 1
-- and u.org_id = 3
-- and u.id = 7
;
create view users_view as (
CREATE VIEW users_view AS (
SELECT
id
, created_at
@@ -113,27 +109,16 @@ SELECT
, instance_id
, org_id
, username
, first_name
, last_name
, description
FROM (
(SELECT
id
, created_at
, updated_at
, deleted_at
, instance_id
, org_id
, username
, tableoid::regclass::TEXT AS type
, first_name
, last_name
, NULL AS description
FROM
human_users)
human_users
UNION
(SELECT
SELECT
id
, created_at
, updated_at
@@ -141,9 +126,10 @@ UNION
, instance_id
, org_id
, username
, tableoid::regclass::TEXT AS type
, NULL AS first_name
, NULL AS last_name
, description
FROM
machine_users)
));
machine_users
);

View File

@@ -0,0 +1,66 @@
package v4
type queryOpts struct {
condition Condition
orderBy Columns
limit uint32
offset uint32
}
func (opts *queryOpts) writeCondition(builder *statementBuilder) {
if opts.condition == nil {
return
}
builder.WriteString(" WHERE ")
opts.condition.writeTo(builder)
}
func (opts *queryOpts) writeOrderBy(builder *statementBuilder) {
if len(opts.orderBy) == 0 {
return
}
builder.WriteString(" ORDER BY ")
opts.orderBy.writeTo(builder)
}
func (opts *queryOpts) writeLimit(builder *statementBuilder) {
if opts.limit == 0 {
return
}
builder.WriteString(" LIMIT ")
builder.writeArg(opts.limit)
}
func (opts *queryOpts) writeOffset(builder *statementBuilder) {
if opts.offset == 0 {
return
}
builder.WriteString(" OFFSET ")
builder.writeArg(opts.offset)
}
type QueryOption func(*queryOpts)
func WithCondition(condition Condition) QueryOption {
return func(opts *queryOpts) {
opts.condition = condition
}
}
func WithOrderBy(orderBy ...Column) QueryOption {
return func(opts *queryOpts) {
opts.orderBy = orderBy
}
}
func WithLimit(limit uint32) QueryOption {
return func(opts *queryOpts) {
opts.limit = limit
}
}
func WithOffset(offset uint32) QueryOption {
return func(opts *queryOpts) {
opts.offset = offset
}
}

View File

@@ -29,17 +29,13 @@ type userTrait interface {
Type() UserType
}
const userQuery = `SELECT u.instance_id, u.org_id, u.id, u.username, u.type, u.created_at, u.updated_at, u.deleted_at,` +
` h.first_name, h.last_name, h.email_address, h.email_verified_at, h.phone_number, h.phone_verified_at, m.description` +
` FROM users u` +
` LEFT JOIN user_humans h ON u.instance_id = h.instance_id AND u.org_id = h.org_id AND u.id = h.id` +
` LEFT JOIN user_machines m ON u.instance_id = m.instance_id AND u.org_id = m.org_id AND u.id = m.id`
const queryUserStmt = `SELECT instance_id, org_id, id, username, type, created_at, updated_at, deleted_at,` +
` first_name, last_name, email_address, email_verified_at, phone_number, phone_verified_at, description` +
` FROM users_view`
type user struct {
builder statementBuilder
client database.QueryExecutor
condition Condition
}
func UserRepository(client database.QueryExecutor) *user {
@@ -48,20 +44,17 @@ func UserRepository(client database.QueryExecutor) *user {
}
}
func (u *user) WithCondition(condition Condition) *user {
u.condition = condition
return u
}
func (u *user) List(ctx context.Context, opts ...QueryOption) (users []*User, err error) {
options := new(queryOpts)
for _, opt := range opts {
opt(options)
}
func (u *user) Get(ctx context.Context) (*User, error) {
u.builder.WriteString(userQuery)
u.writeCondition()
return scanUser(u.client.QueryRow(ctx, u.builder.String(), u.builder.args...))
}
func (u *user) List(ctx context.Context) (users []*User, err error) {
u.builder.WriteString(userQuery)
u.writeCondition()
u.builder.WriteString(queryUserStmt)
options.writeCondition(&u.builder)
options.writeOrderBy(&u.builder)
options.writeLimit(&u.builder)
options.writeOffset(&u.builder)
rows, err := u.client.Query(ctx, u.builder.String(), u.builder.args...)
if err != nil {
@@ -87,7 +80,23 @@ func (u *user) List(ctx context.Context) (users []*User, err error) {
return users, nil
}
func (u *user) Get(ctx context.Context, opts ...QueryOption) (*User, error) {
options := new(queryOpts)
for _, opt := range opts {
opt(options)
}
u.builder.WriteString(queryUserStmt)
options.writeCondition(&u.builder)
options.writeOrderBy(&u.builder)
options.writeLimit(&u.builder)
options.writeOffset(&u.builder)
return scanUser(u.client.QueryRow(ctx, u.builder.String(), u.builder.args...))
}
const (
// TODO: change to separate statements and tables
createUserCte = `WITH user AS (` +
`INSERT INTO users (instance_id, org_id, id, username, type) VALUES ($1, $2, $3, $4, $5)` +
` RETURNING *)`
@@ -111,11 +120,24 @@ func (u *user) Create(ctx context.Context, user *User) error {
u.builder.WriteString(createMachineStmt)
u.builder.appendArgs(trait.Description)
}
return u.client.QueryRow(ctx, u.builder.String(), u.builder.args...).Scan(user.CreatedAt, user.UpdatedAt)
return u.client.QueryRow(ctx, u.builder.String(), u.builder.args...).Scan(&user.Dates.CreatedAt, &user.Dates.UpdatedAt)
}
func (u *user) Update(ctx context.Context, condition Condition, changes ...Change) error {
u.builder.WriteString("UPDATE users SET ")
Changes(changes).writeTo(&u.builder)
u.writeCondition(condition)
return u.client.Exec(ctx, u.builder.String(), u.builder.args...)
}
func (u *user) Delete(ctx context.Context, condition Condition) error {
u.builder.WriteString("DELETE FROM users")
u.writeCondition(condition)
return u.client.Exec(ctx, u.builder.String(), u.builder.args...)
}
func (u *user) InstanceIDColumn() Column {
return column{name: "u.instance_id"}
return column{name: "instance_id"}
}
func (u *user) InstanceIDCondition(instanceID string) Condition {
@@ -123,7 +145,7 @@ func (u *user) InstanceIDCondition(instanceID string) Condition {
}
func (u *user) OrgIDColumn() Column {
return column{name: "u.org_id"}
return column{name: "org_id"}
}
func (u *user) OrgIDCondition(orgID string) Condition {
@@ -131,7 +153,7 @@ func (u *user) OrgIDCondition(orgID string) Condition {
}
func (u *user) IDColumn() Column {
return column{name: "u.id"}
return column{name: "id"}
}
func (u *user) IDCondition(userID string) Condition {
@@ -140,7 +162,7 @@ func (u *user) IDCondition(userID string) Condition {
func (u *user) UsernameColumn() Column {
return ignoreCaseCol{
column: column{name: "u.username"},
column: column{name: "username"},
suffix: "_lower",
}
}
@@ -154,7 +176,7 @@ func (u *user) UsernameCondition(op TextOperator, username string) Condition {
}
func (u *user) CreatedAtColumn() Column {
return column{name: "u.created_at"}
return column{name: "created_at"}
}
func (u *user) CreatedAtCondition(op NumberOperator, createdAt time.Time) Condition {
@@ -162,7 +184,7 @@ func (u *user) CreatedAtCondition(op NumberOperator, createdAt time.Time) Condit
}
func (u *user) UpdatedAtColumn() Column {
return column{name: "u.updated_at"}
return column{name: "updated_at"}
}
func (u *user) UpdatedAtCondition(op NumberOperator, updatedAt time.Time) Condition {
@@ -170,7 +192,7 @@ func (u *user) UpdatedAtCondition(op NumberOperator, updatedAt time.Time) Condit
}
func (u *user) DeletedAtColumn() Column {
return column{name: "u.deleted_at"}
return column{name: "deleted_at"}
}
func (u *user) DeletedCondition(isDeleted bool) Condition {
@@ -184,12 +206,24 @@ func (u *user) DeletedAtCondition(op NumberOperator, deletedAt time.Time) Condit
return newNumberCondition(u.DeletedAtColumn(), op, deletedAt)
}
func (u *user) writeCondition() {
if u.condition == nil {
func (u *user) writeCondition(condition Condition) {
if condition == nil {
return
}
u.builder.WriteString(" WHERE ")
u.condition.writeTo(&u.builder)
condition.writeTo(&u.builder)
}
func (u user) columns() Columns {
return Columns{
u.InstanceIDColumn(),
u.OrgIDColumn(),
u.IDColumn(),
u.UsernameColumn(),
u.CreatedAtColumn(),
u.UpdatedAtColumn(),
u.DeletedAtColumn(),
}
}
func scanUser(scanner database.Scanner) (*User, error) {

View File

@@ -46,11 +46,11 @@ func (u *user) Human() *userHuman {
const userEmailQuery = `SELECT h.email_address, h.email_verified_at FROM user_humans h`
func (u *userHuman) GetEmail(ctx context.Context) (*Email, error) {
func (u *userHuman) GetEmail(ctx context.Context, condition Condition) (*Email, error) {
var email Email
u.builder.WriteString(userEmailQuery)
u.writeCondition()
u.writeCondition(condition)
err := u.client.QueryRow(ctx, u.builder.String(), u.builder.args...).Scan(
&email.Address,
@@ -63,10 +63,10 @@ func (u *userHuman) GetEmail(ctx context.Context) (*Email, error) {
return &email, nil
}
func (h userHuman) Update(ctx context.Context, changes ...Change) error {
h.builder.WriteString(`UPDATE human_users h SET `)
func (h userHuman) Update(ctx context.Context, condition Condition, changes ...Change) error {
h.builder.WriteString(`UPDATE human_users SET `)
Changes(changes).writeTo(&h.builder)
h.writeCondition()
h.writeCondition(condition)
stmt := h.builder.String()
@@ -78,7 +78,7 @@ func (h userHuman) SetFirstName(firstName string) Change {
}
func (h userHuman) FirstNameColumn() Column {
return column{"h.first_name"}
return column{"first_name"}
}
func (h userHuman) FirstNameCondition(op TextOperator, firstName string) Condition {
@@ -90,7 +90,7 @@ func (h userHuman) SetLastName(lastName string) Change {
}
func (h userHuman) LastNameColumn() Column {
return column{"h.last_name"}
return column{"last_name"}
}
func (h userHuman) LastNameCondition(op TextOperator, lastName string) Condition {
@@ -99,7 +99,7 @@ func (h userHuman) LastNameCondition(op TextOperator, lastName string) Condition
func (h userHuman) EmailAddressColumn() Column {
return ignoreCaseCol{
column: column{"h.email_address"},
column: column{"email_address"},
suffix: "_lower",
}
}
@@ -109,7 +109,7 @@ func (h userHuman) EmailAddressCondition(op TextOperator, email string) Conditio
}
func (h userHuman) EmailVerifiedAtColumn() Column {
return column{"h.email_verified_at"}
return column{"email_verified_at"}
}
func (h *userHuman) EmailAddressVerifiedCondition(isVerified bool) Condition {
@@ -144,7 +144,7 @@ func (h userHuman) SetEmail(address string, verified *time.Time) Change {
}
func (h userHuman) PhoneNumberColumn() Column {
return column{"h.phone_number"}
return column{"phone_number"}
}
func (h userHuman) SetPhoneNumber(number string) Change {
@@ -156,7 +156,7 @@ func (h userHuman) PhoneNumberCondition(op TextOperator, phoneNumber string) Con
}
func (h userHuman) PhoneVerifiedAtColumn() Column {
return column{"h.phone_verified_at"}
return column{"phone_verified_at"}
}
func (h userHuman) PhoneNumberVerifiedCondition(isVerified bool) Condition {
@@ -185,3 +185,19 @@ func (h userHuman) SetPhone(number string, verifiedAt *time.Time) Change {
newUpdatePtrColumn(h.PhoneVerifiedAtColumn(), verifiedAt),
)
}
func (h userHuman) columns() Columns {
return append(h.user.columns(),
h.FirstNameColumn(),
h.LastNameColumn(),
h.EmailAddressColumn(),
h.EmailVerifiedAtColumn(),
h.PhoneNumberColumn(),
h.PhoneVerifiedAtColumn(),
)
}
func (h userHuman) writeReturning(builder *statementBuilder) {
builder.WriteString(" RETURNING ")
h.columns().writeTo(builder)
}

View File

@@ -24,12 +24,34 @@ func (u *user) Machine() *userMachine {
return &userMachine{user: u}
}
func (m userMachine) Update(ctx context.Context, cols ...Change) (*Machine, error) {
return nil, nil
func (m userMachine) Update(ctx context.Context, condition Condition, changes ...Change) ([]*Machine, error) {
m.builder.WriteString("UPDATE user_machines SET ")
Changes(changes).writeTo(&m.builder)
m.writeCondition(condition)
m.writeReturning()
var machines []*Machine
rows, err := m.client.Query(ctx, m.builder.String(), m.builder.args...)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
machine := new(Machine)
if err := rows.Scan(&machine.Description); err != nil {
return nil, err
}
machines = append(machines, machine)
}
if err := rows.Err(); err != nil {
return nil, err
}
return machines, nil
}
func (userMachine) DescriptionColumn() Column {
return column{"m.description"}
return column{"description"}
}
func (m userMachine) SetDescription(description string) Change {
@@ -39,3 +61,12 @@ func (m userMachine) SetDescription(description string) Change {
func (m userMachine) DescriptionCondition(op TextOperator, description string) Condition {
return newTextCondition(m.DescriptionColumn(), op, description)
}
func (m userMachine) columns() Columns {
return append(m.user.columns(), m.DescriptionColumn())
}
func (m *userMachine) writeReturning() {
m.builder.WriteString(" RETURNING ")
m.columns().writeTo(&m.builder)
}

View File

@@ -11,7 +11,8 @@ import (
func TestQueryUser(t *testing.T) {
t.Run("User filters", func(t *testing.T) {
user := v4.UserRepository(nil)
user.WithCondition(
u, err := user.Get(context.Background(),
v4.WithCondition(
v4.And(
v4.Or(
user.IDCondition("test"),
@@ -19,24 +20,29 @@ func TestQueryUser(t *testing.T) {
),
user.UsernameCondition(v4.TextOperatorStartsWithIgnoreCase, "test"),
),
).Get(context.Background())
),
v4.WithOrderBy(user.CreatedAtColumn()),
)
assert.NoError(t, err)
assert.NotNil(t, u)
})
t.Run("machine and human filters", func(t *testing.T) {
user := v4.UserRepository(nil)
machine := user.Machine()
human := user.Human()
user.WithCondition(
v4.And(
email, err := human.GetEmail(context.Background(), v4.And(
user.UsernameCondition(v4.TextOperatorStartsWithIgnoreCase, "test"),
v4.Or(
machine.DescriptionCondition(v4.TextOperatorStartsWithIgnoreCase, "test"),
human.EmailAddressVerifiedCondition(true),
v4.IsNotNull(machine.DescriptionColumn()),
),
),
)
human.GetEmail(context.Background())
))
assert.NoError(t, err)
assert.NotNil(t, email)
})
}
@@ -56,10 +62,6 @@ func TestArg(t *testing.T) {
func TestWriteUser(t *testing.T) {
t.Run("update user", func(t *testing.T) {
user := v4.UserRepository(nil)
user.WithCondition(user.IDCondition("test")).Human().Update(
context.Background(),
user.SetUsername("test"),
)
user.Update(context.Background(), user.IDCondition("test"), user.SetUsername("test"))
})
}