Browse Source

Add clients for our new database

pull/1/head
Stephanie Gredell 7 months ago
parent
commit
ad9b342605
  1. 7
      go.mod
  2. 8
      go.sum
  3. 94
      internals/db/progress.go
  4. 64
      internals/db/subscriptions.go
  5. 57
      internals/db/users.go

7
go.mod

@ -7,4 +7,11 @@ toolchain go1.23.10
require ( require (
github.com/golang-jwt/jwt/v5 v5.2.2 github.com/golang-jwt/jwt/v5 v5.2.2
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d
)
require (
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/coder/websocket v1.8.12 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
) )

8
go.sum

@ -1,4 +1,12 @@
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=

94
internals/db/progress.go

@ -0,0 +1,94 @@
package db
import (
"context"
"database/sql"
"errors"
"time"
_ "github.com/tursodatabase/libsql-client-go/libsql"
)
type Progress struct {
ID string
UserID string
LevelID string
Status string
CompletedAt sql.NullTime
AttemptData sql.NullString
Stars sql.NullInt64
CreatedAt time.Time
UpdatedAt time.Time
}
type ProgressClient struct {
db *sql.DB
}
func NewProgressClient(db *sql.DB) *ProgressClient {
return &ProgressClient{db: db}
}
func (c *ProgressClient) UpsertProgress(ctx context.Context, p *Progress) error {
_, err := c.db.ExecContext(ctx, `
INSERT INTO progress (id, user_id, level_id, status, completed_at, attempt_data, stars)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(user_id, level_id) DO UPDATE SET
status = excluded.status,
completed_at = excluded.completed_at,
attempt_data = excluded.attempt_data,
stars = excluded.stars,
updated_at = CURRENT_TIMESTAMP
`, p.ID, p.UserID, p.LevelID, p.Status, p.CompletedAt, p.AttemptData, p.Stars)
return err
}
func (c *ProgressClient) GetProgressByUser(ctx context.Context, userID string) ([]*Progress, error) {
rows, err := c.db.QueryContext(ctx, `
SELECT id, user_id, level_id, status, completed_at, attempt_data, stars, created_at, updated_at
FROM progress
WHERE user_id = ?
`, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var progressList []*Progress
for rows.Next() {
var p Progress
err := rows.Scan(&p.ID, &p.UserID, &p.LevelID, &p.Status, &p.CompletedAt, &p.AttemptData, &p.Stars, &p.CreatedAt, &p.UpdatedAt)
if err != nil {
return nil, err
}
progressList = append(progressList, &p)
}
return progressList, nil
}
func (c *ProgressClient) GetProgress(ctx context.Context, userID, levelID string) (*Progress, error) {
row := c.db.QueryRowContext(ctx, `
SELECT id, user_id, level_id, status, completed_at, attempt_data, stars, created_at, updated_at
FROM progress
WHERE user_id = ? AND level_id = ?
`, userID, levelID)
var p Progress
err := row.Scan(&p.ID, &p.UserID, &p.LevelID, &p.Status, &p.CompletedAt, &p.AttemptData, &p.Stars, &p.CreatedAt, &p.UpdatedAt)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, err
}
return &p, nil
}
func (c *ProgressClient) DeleteProgress(ctx context.Context, userID, levelID string) error {
_, err := c.db.ExecContext(ctx, `
DELETE FROM progress
WHERE user_id = ? AND level_id = ?
`, userID, levelID)
return err
}

64
internals/db/subscriptions.go

@ -0,0 +1,64 @@
package db
import (
"context"
"database/sql"
"time"
_ "github.com/tursodatabase/libsql-client-go/libsql"
)
type Subscription struct {
ID string
UserID string
StripeID string
Status string
StartedAt time.Time
EndsAt sql.NullTime
}
type SubscriptionClient struct {
db *sql.DB
}
func NewSubscriptionClient(db *sql.DB) *SubscriptionClient {
return &SubscriptionClient{db: db}
}
// Insert or update subscription
func (c *SubscriptionClient) Upsert(ctx context.Context, s *Subscription) error {
_, err := c.db.ExecContext(ctx, `
INSERT INTO subscriptions (id, user_id, stripe_id, status, started_at, ends_at)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT(id) DO UPDATE SET
status = excluded.status,
started_at = excluded.started_at,
ends_at = excluded.ends_at
`, s.ID, s.UserID, s.StripeID, s.Status, s.StartedAt, s.EndsAt)
return err
}
// Get by user ID
func (c *SubscriptionClient) GetByUserID(ctx context.Context, userID string) (*Subscription, error) {
row := c.db.QueryRowContext(ctx, `
SELECT id, user_id, stripe_id, status, started_at, ends_at
FROM subscriptions
WHERE user_id = ?
`, userID)
var s Subscription
err := row.Scan(&s.ID, &s.UserID, &s.StripeID, &s.Status, &s.StartedAt, &s.EndsAt)
if err != nil {
return nil, err
}
return &s, nil
}
// Delete by user ID
func (c *SubscriptionClient) DeleteByUserID(ctx context.Context, userID string) error {
_, err := c.db.ExecContext(ctx, `
DELETE FROM subscriptions
WHERE user_id = ?
`, userID)
return err
}

57
internals/db/users.go

@ -0,0 +1,57 @@
package db
import (
"context"
"database/sql"
"time"
_ "github.com/tursodatabase/libsql-client-go/libsql"
)
type User struct {
ID string
GitHubID int64
GitHubLogin string
AvatarURL string
Email string
CreatedAt time.Time
UpdatedAt time.Time
}
type UserClient struct {
db *sql.DB
}
func NewUserClient(db *sql.DB) *UserClient {
return &UserClient{db: db}
}
func (uc *UserClient) UpsertUser(ctx context.Context, user User) error {
_, err := uc.db.ExecContext(ctx, `
INSERT INTO users (id, github_id, github_login, avatar_url, email)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT(github_id) DO UPDATE SET
github_login = excluded.github_login,
avatar_url = excluded.avatar_url,
email = excluded.email,
updated_at = CURRENT_TIMESTAMP
`, user.ID, user.GitHubID, user.GitHubLogin, user.AvatarURL, user.Email)
return err
}
func (uc *UserClient) GetUserByGitHubID(ctx context.Context, githubID int64) (*User, error) {
row := uc.db.QueryRowContext(ctx, `
SELECT id, github_id, github_login, avatar_url, email, created_at, updated_at
FROM users WHERE github_id = ?
`, githubID)
var user User
err := row.Scan(
&user.ID, &user.GitHubID, &user.GitHubLogin,
&user.AvatarURL, &user.Email, &user.CreatedAt, &user.UpdatedAt,
)
if err == sql.ErrNoRows {
return nil, nil
}
return &user, err
}
Loading…
Cancel
Save