diff --git a/go/api/api.go b/go/api/api.go index 5c42f4c..17d280f 100644 --- a/go/api/api.go +++ b/go/api/api.go @@ -3,6 +3,7 @@ package api import ( "sync" + "github.com/go-jet/jet/v2/qrm" "github.com/stephenafamo/bob" "github.com/tigorlazuardi/bluemage/go/gen/converter" ) @@ -10,8 +11,9 @@ import ( var convert converter.DeviceConverterImpl type API struct { - mu sync.Mutex - DB bob.Executor + mu sync.Mutex + Executor bob.Executor + DB qrm.Queryable } func (api *API) lockf(f func()) { diff --git a/go/api/devices_count.go b/go/api/devices_count.go index 14cdeb1..bdcc3a3 100644 --- a/go/api/devices_count.go +++ b/go/api/devices_count.go @@ -31,7 +31,7 @@ func queryFromCountDevicesRequest(req *device.CountDevicesRequest) (expr []bob.M } func (api *API) DevicesCount(ctx context.Context, request *device.CountDevicesRequest) (uint64, error) { - count, err := models.Devices.Query(ctx, api.DB, queryFromCountDevicesRequest(request)...).Count() + count, err := models.Devices.Query(ctx, api.Executor, queryFromCountDevicesRequest(request)...).Count() if err != nil { return 0, errs.Wrapw(err, "failed to count devices", "request", request) } diff --git a/go/api/devices_create.go b/go/api/devices_create.go index 7776603..8cd2702 100644 --- a/go/api/devices_create.go +++ b/go/api/devices_create.go @@ -17,7 +17,7 @@ func (api *API) DevicesCreate(ctx context.Context, params *models.Device) (devic ctx, coll := log.WithQueryCollector(ctx) now := time.Now() api.lockf(func() { - device, err = models.Devices.Insert(ctx, api.DB, &models.DeviceSetter{ + device, err = models.Devices.Insert(ctx, api.Executor, &models.DeviceSetter{ Slug: omit.From(params.Slug), Name: omit.From(params.Name), ResolutionX: omit.From(params.ResolutionX), diff --git a/go/api/devices_exist.go b/go/api/devices_exist.go index 25cc255..3bbe3bd 100644 --- a/go/api/devices_exist.go +++ b/go/api/devices_exist.go @@ -10,7 +10,7 @@ import ( func (api *API) DevicesExist(ctx context.Context, slug string) (exists bool, err error) { ctx, coll := log.WithQueryCollector(ctx) - exists, err = models.DeviceExists(ctx, api.DB, slug) + exists, err = models.DeviceExists(ctx, api.Executor, slug) if err != nil { return exists, errs.Wrapw(err, "failed to check device existence", "slug", slug, diff --git a/go/api/devices_get_by_slug.go b/go/api/devices_get_by_slug.go index b958e63..430a62e 100644 --- a/go/api/devices_get_by_slug.go +++ b/go/api/devices_get_by_slug.go @@ -11,7 +11,7 @@ import ( func (api *API) GetDevice(ctx context.Context, slug string) (device *models.Device, err error) { ctx, coll := log.WithQueryCollector(ctx) - device, err = models.FindDevice(ctx, api.DB, slug) + device, err = models.FindDevice(ctx, api.Executor, slug) if err != nil { if err.Error() == "sql: no rows in result set" { return device, errs.Wrapw(err, "device not found", diff --git a/go/api/devices_list.go b/go/api/devices_list.go index f5a289a..cbaa532 100644 --- a/go/api/devices_list.go +++ b/go/api/devices_list.go @@ -57,7 +57,7 @@ func queryFromListDeviceRequest(req *device.ListDevicesRequest) (expr []bob.Mod[ func (api *API) DevicesList(ctx context.Context, req *device.ListDevicesRequest) (resp *device.ListDevicesResponse, err error) { resp = &device.ListDevicesResponse{} - results, err := models.Devices.Query(ctx, api.DB, queryFromListDeviceRequest(req)...).All() + results, err := models.Devices.Query(ctx, api.Executor, queryFromListDeviceRequest(req)...).All() if err != nil { return resp, errs.Wrapw(err, "failed to list devices", "request", req) } diff --git a/go/api/devices_update.go b/go/api/devices_update.go index b921e88..8733750 100644 --- a/go/api/devices_update.go +++ b/go/api/devices_update.go @@ -25,7 +25,7 @@ func (api *API) DevicesUpdate(ctx context.Context, slug string, update *models.D target := &models.Device{Slug: slug} api.lockf(func() { - err = models.Devices.Update(ctx, api.DB, update, target) + err = models.Devices.Update(ctx, api.Executor, update, target) }) if err != nil { if sqlite3Err := new(sqlite3.Error); errors.As(err, &sqlite3Err) { diff --git a/go/api/subreddits_create.go b/go/api/subreddits_create.go index 980b969..9c5c07b 100644 --- a/go/api/subreddits_create.go +++ b/go/api/subreddits_create.go @@ -15,7 +15,7 @@ func (api *API) SubredditCreate(ctx context.Context, subreddit *models.Subreddit // TODO: add check to Reddit API to see if subreddit exists. api.lockf(func() { - _, err = models.Subreddits.Insert(ctx, api.DB, &models.SubredditSetter{ + _, err = models.Subreddits.Insert(ctx, api.Executor, &models.SubredditSetter{ Name: omit.From(subreddit.Name), DisableScheduler: omit.From(subreddit.DisableScheduler), Type: omit.From(subreddit.Type), diff --git a/go/api/subreddits_get.go b/go/api/subreddits_get.go new file mode 100644 index 0000000..50a24d6 --- /dev/null +++ b/go/api/subreddits_get.go @@ -0,0 +1,53 @@ +package api + +import ( + "context" + "errors" + + "connectrpc.com/connect" + "github.com/tigorlazuardi/bluemage/go/gen/jet/model" + "github.com/tigorlazuardi/bluemage/go/pkg/errs" + "github.com/tigorlazuardi/bluemage/go/pkg/telemetry" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + "github.com/go-jet/jet/v2/qrm" + + . "github.com/go-jet/jet/v2/sqlite" + . "github.com/tigorlazuardi/bluemage/go/gen/jet/table" +) + +var getSubredditMetric, _ = meter.Int64Counter("api.subreddits.get", + metric.WithDescription("The number of times a subreddit is retrieved"), +) + +func (api *API) GetSubreddit(ctx context.Context, name string) (sub model.Subreddits, err error) { + ctx, span := tracer.Start(ctx, "GetSubreddit", trace.WithAttributes(attribute.String("name", name))) + defer func() { telemetry.EndWithStatus(span, err) }() + + getSubredditMetric.Add(ctx, 1, metric.WithAttributes(attribute.String("name", name))) + + stmt := SELECT(Subreddits.AllColumns). + FROM(Subreddits). + WHERE(Subreddits.Name.EQ(String(name))) + + err = stmt.QueryContext(ctx, api.DB, &sub) + if err != nil { + if errors.Is(err, qrm.ErrNoRows) { + return sub, errs. + Wrapf(err, "subreddit '%s' does not exist", name). + Details( + "name", name, + "query", stmt.DebugSql(), + ). + Code(connect.CodeNotFound) + } + return sub, errs.Wrapf(err, "failed to get subreddit '%s'", name). + Details( + "name", name, + "query", stmt.DebugSql(), + ) + } + return sub, nil +} diff --git a/go/api/telemetry.go b/go/api/telemetry.go new file mode 100644 index 0000000..ca96673 --- /dev/null +++ b/go/api/telemetry.go @@ -0,0 +1,8 @@ +package api + +import "go.opentelemetry.io/otel" + +var ( + tracer = otel.Tracer("github.com/tigorlazuardi/bluemage/go/api") + meter = otel.Meter("github.com/tigorlazuardi/bluemage/go/api") +) diff --git a/go/cmd/bluemage/serve/serve.go b/go/cmd/bluemage/serve/serve.go index f715962..6fd965d 100644 --- a/go/cmd/bluemage/serve/serve.go +++ b/go/cmd/bluemage/serve/serve.go @@ -77,7 +77,8 @@ var Cmd = &cobra.Command{ db := bob.New(sqldb) api := &api.API{ - DB: db, + Executor: db, + DB: sqldb, } handler := &server.Server{