package main import ( "context" "atlas9.dev/c/core" "atlas9.dev/c/core/dbi" "atlas9.dev/c/core/iam" ) type SqliteUserStore struct { db dbi.DBI } var _ iam.UserStore = (*SqliteUserStore)(nil) func NewSqliteUserStore(db dbi.DBI) *SqliteUserStore { return &SqliteUserStore{db: db} } func (s *SqliteUserStore) Save(ctx context.Context, user *iam.User) (bool, error) { if user.ID.IsZero() { user.ID = core.NewID() } res, err := s.db.Exec(ctx, ` INSERT INTO users (id, email, verified) VALUES ($1, $2, $3) ON CONFLICT (email) DO NOTHING `, user.ID, user.Email, user.Verified) if err != nil { return false, err } n, err := res.RowsAffected() if err != nil { return false, err } created := n > 0 if !created { // emails are unique, so if there's a conflict on email, fetch the existing ID. err = dbi.Get(ctx, s.db, user, `SELECT id, verified FROM users WHERE email = $1`, user.Email) } return created, err } func (s *SqliteUserStore) GetByEmail(ctx context.Context, email string) (*iam.User, error) { var user iam.User err := dbi.Get(ctx, s.db, &user, `SELECT id, email, verified FROM users WHERE email = $1`, email) return &user, err } func (s *SqliteUserStore) Get(ctx context.Context, id core.ID) (*iam.User, error) { var user iam.User err := dbi.Get(ctx, s.db, &user, `SELECT id, email, verified FROM users WHERE id = $1`, id) return &user, err } func (s *SqliteUserStore) Verify(ctx context.Context, id core.ID) error { _, err := s.db.Exec(ctx, `UPDATE users SET verified = true WHERE id = $1`, id) return err } func (s *SqliteUserStore) List(ctx context.Context, page core.PageReq) (core.Page[iam.User], error) { limit := page.Limit if limit <= 0 { limit = 100 } rows, err := s.db.Query(ctx, ` SELECT id, email, verified FROM users WHERE id > $1 ORDER BY id LIMIT $2 `, page.Cursor, limit) if err != nil { return core.Page[iam.User]{}, err } defer rows.Close() var items []iam.User for rows.Next() { var u iam.User if err := rows.Scan(&u.ID, &u.Email, &u.Verified); err != nil { return core.Page[iam.User]{}, err } items = append(items, u) } if err := rows.Err(); err != nil { return core.Page[iam.User]{}, err } var cursor string if len(items) == limit { cursor = items[limit-1].ID.String() } return core.Page[iam.User]{Items: items, Cursor: cursor}, nil }