package store import ( "context" "database/sql" "time" "atlas9.dev/c/core" "atlas9.dev/c/core/dbi" "atlas9.dev/c/demo/lib" "atlas9.dev/c/demo/lib/domains" ) type SqliteDomainStore struct { db dbi.DBI guard lib.Guard } // GetByName implements [domains.Store]. func (s *SqliteDomainStore) GetByName(ctx context.Context, name string) (*domains.Domain, error) { var rec sqlDomain err := dbi.Get(ctx, s.db, &rec, `SELECT id, tenant, domain, verified_at FROM domains WHERE domain = $1`, name) if err != nil { return nil, err } var out domains.Domain out.ID = rec.ID out.Tenant = rec.Tenant out.Domain = rec.Domain out.VerifiedAt = nil if rec.VerifiedAt.Valid { out.VerifiedAt = &rec.VerifiedAt.Time } return &out, nil } var _ domains.Store = (*SqliteDomainStore)(nil) func NewSqliteDomainStore(db dbi.DBI, guard lib.Guard) *SqliteDomainStore { return &SqliteDomainStore{db: db, guard: guard} } // Create implements [domains.Store]. func (s *SqliteDomainStore) Create(ctx context.Context, d *domains.Domain) error { if err := s.guard.Check(ctx, domains.Cap_Domain_Write, d.Tenant, ""); err != nil { return err } _, err := s.db.Exec(ctx, ` INSERT INTO domains (id, tenant, domain, verified_at) VALUES ($1, $2, $3, $4) `, d.ID, d.Tenant, d.Domain, d.VerifiedAt) return err } // SetVerifiedAt implements [domains.Store]. func (s *SqliteDomainStore) SetVerifiedAt(ctx context.Context, tenant core.ID, id core.ID, verifiedAt time.Time) error { if err := s.guard.Check(ctx, domains.Cap_Domain_Write, tenant, ""); err != nil { return err } _, err := s.db.Exec(ctx, `UPDATE domains SET verified_at = $1 WHERE id = $2 AND tenant = $3`, verifiedAt, id, tenant) return err } // Delete implements [domains.Store]. func (s *SqliteDomainStore) Delete(ctx context.Context, tenant core.ID, id core.ID) error { if err := s.guard.Check(ctx, domains.Cap_Domain_Write, tenant, ""); err != nil { return err } _, err := s.db.Exec(ctx, `DELETE FROM domains WHERE id = $1 AND tenant = $2`, id, tenant) return err } // Get implements [domains.Store]. func (s *SqliteDomainStore) Get(ctx context.Context, tenant core.ID, id core.ID, out *domains.Domain) error { if err := s.guard.Check(ctx, domains.Cap_Domain_Read, tenant, ""); err != nil { return err } var rec sqlDomain err := dbi.Get(ctx, s.db, &rec, `SELECT id, tenant, domain, verified_at FROM domains WHERE id = $1 AND tenant = $2`, id, tenant) if err != nil { return err } out.ID = rec.ID out.Tenant = rec.Tenant out.Domain = rec.Domain out.VerifiedAt = nil if rec.VerifiedAt.Valid { out.VerifiedAt = &rec.VerifiedAt.Time } return nil } // List implements [domains.Store]. func (s *SqliteDomainStore) List(ctx context.Context, tenant core.ID, page core.PageReq, out *core.Page[domains.Domain]) error { if err := s.guard.Check(ctx, domains.Cap_Domain_Read, tenant, ""); err != nil { return err } recs := core.Page[sqlDomain]{} err := dbi.Paginate(ctx, s.db, page, &recs, func(d sqlDomain) string { return d.ID.String() }, `SELECT id, tenant, domain, verified_at FROM domains WHERE tenant = $1 AND id > $cursor ORDER BY id LIMIT $limit`, tenant) if err != nil { return err } out.Cursor = recs.Cursor out.Items = make([]domains.Domain, len(recs.Items)) for i, it := range recs.Items { d := domains.Domain{ ID: it.ID, Tenant: it.Tenant, Domain: it.Domain, } if it.VerifiedAt.Valid { d.VerifiedAt = &it.VerifiedAt.Time } out.Items[i] = d } return nil } type sqlDomain struct { ID core.ID Tenant core.ID Domain string VerifiedAt sql.NullTime }