From eb90c0a68e75bb19754c16e97c593521251b3915 Mon Sep 17 00:00:00 2001 From: Kevin Lyda <kevin@lyda.ie> Date: Mon, 25 Nov 2024 22:42:36 +0000 Subject: [PATCH] Queries mostly debugged --- api/boxes.yaml | 10 +- database/migrations/01_initial.up.sql | 18 +-- database/query.sql | 8 ++ server/boxes.go | 134 ++++++++++++++++++++ server/contents.go | 161 ++++++++++++++++++++++++ server/endpoints.go | 175 -------------------------- server/locations.go | 127 +++++++++++++++++++ server/server.go | 14 ++- 8 files changed, 458 insertions(+), 189 deletions(-) create mode 100644 server/boxes.go create mode 100644 server/contents.go create mode 100644 server/locations.go diff --git a/api/boxes.yaml b/api/boxes.yaml index 09eb77a..1f95a39 100644 --- a/api/boxes.yaml +++ b/api/boxes.yaml @@ -196,13 +196,13 @@ paths: '500': $ref: '#/components/responses/Error' - /content/{bid}: + /content/{cid}: get: summary: Content description: Get a content. operationId: GetContent parameters: - - $ref: '#/components/parameters/BID' + - $ref: '#/components/parameters/CID' responses: '200': $ref: '#/components/responses/Content' @@ -215,7 +215,7 @@ paths: description: Create a content. operationId: CreateContent parameters: - - $ref: '#/components/parameters/BID' + - $ref: '#/components/parameters/CID' requestBody: description: New content. required: true @@ -237,7 +237,7 @@ paths: description: Update a content. operationId: UpdateContent parameters: - - $ref: '#/components/parameters/BID' + - $ref: '#/components/parameters/CID' requestBody: description: Updated content. required: true @@ -261,7 +261,7 @@ paths: description: Delete content. operationId: DeleteContent parameters: - - $ref: '#/components/parameters/BID' + - $ref: '#/components/parameters/CID' responses: '200': $ref: '#/components/responses/Content' diff --git a/database/migrations/01_initial.up.sql b/database/migrations/01_initial.up.sql index 38b032b..d60b655 100644 --- a/database/migrations/01_initial.up.sql +++ b/database/migrations/01_initial.up.sql @@ -1,19 +1,21 @@ -CREATE TABLE IF NOT EXISTS contents ( +CREATE TABLE IF NOT EXISTS locations ( id TEXT PRIMARY KEY, - box TEXT NOT NULL, - description TEXT NOT NULL, - tags TEXT + description TEXT NOT NULL ) WITHOUT ROWID; -CREATE INDEX IF NOT EXISTS contents_box_idx ON contents(box); CREATE TABLE IF NOT EXISTS boxes ( id TEXT PRIMARY KEY, location TEXT NOT NULL, - description TEXT NOT NULL + description TEXT NOT NULL, + FOREIGN KEY(location) REFERENCES locations(id) ) WITHOUT ROWID; CREATE INDEX IF NOT EXISTS boxes_location_idx ON boxes(location); -CREATE TABLE IF NOT EXISTS locations ( +CREATE TABLE IF NOT EXISTS contents ( id TEXT PRIMARY KEY, - description TEXT NOT NULL + box TEXT NOT NULL, + description TEXT NOT NULL, + tags TEXT, + FOREIGN KEY(box) REFERENCES boxes(id) ) WITHOUT ROWID; +CREATE INDEX IF NOT EXISTS contents_box_idx ON contents(box); diff --git a/database/query.sql b/database/query.sql index 8219b76..4e8da7c 100644 --- a/database/query.sql +++ b/database/query.sql @@ -50,6 +50,10 @@ RETURNING *; -- name: GetBoxes :many SELECT * FROM boxes; +-- name: GetBoxesWithFilter :many +SELECT * FROM boxes +WHERE description LIKE ?; + -- name: GetContent :one SELECT * FROM contents WHERE id = ? LIMIT 1; @@ -74,4 +78,8 @@ RETURNING *; -- name: GetContents :many SELECT * FROM contents; +-- name: GetContentsWithFilter :many +SELECT * FROM contents +WHERE description LIKE ?; + -- vim:et diff --git a/server/boxes.go b/server/boxes.go new file mode 100644 index 0000000..b526eb6 --- /dev/null +++ b/server/boxes.go @@ -0,0 +1,134 @@ +// Package server implements the server. +package server + +import ( + "context" + "fmt" + "log" + + "git.lyda.ie/kevin/boxes/api" + "git.lyda.ie/kevin/boxes/database/store" +) + +// GetBox TODO. +func (ep *Endpoints) GetBox(ctx context.Context, req api.GetBoxRequestObject) (api.GetBoxResponseObject, error) { + box, err := ep.db.GetBox(ctx, req.Bid) + if err != nil { + log.Printf("error: %+v", err) + return api.GetBox404JSONResponse{ + Code: 404, + Message: "Not found", + }, nil + } + return api.GetBox200JSONResponse{ + BoxJSONResponse: api.BoxJSONResponse{ + Id: box.ID, + Location: box.Location, + Description: box.Description, + }}, nil +} + +// CreateBox TODO. +func (ep *Endpoints) CreateBox(ctx context.Context, req api.CreateBoxRequestObject) (api.CreateBoxResponseObject, error) { + if req.Bid != req.Body.Id { + log.Printf("error: %+v != %+v", req.Bid, req.Body) + return api.CreateBox406JSONResponse{ + Code: 406, + Message: "Path id not equal to sent id", + }, nil + } + newBox := store.CreateBoxParams{ + ID: req.Bid, + Location: req.Body.Location, + Description: req.Body.Description, + } + result, err := ep.db.CreateBox(ctx, newBox) + if err != nil { + log.Printf("error: %+v", err) + return api.CreateBox507JSONResponse{ + Code: 507, + Message: "Failed to store", + }, nil + } + return api.CreateBox200JSONResponse{ + BoxJSONResponse: api.BoxJSONResponse{ + Id: result.ID, + Location: result.Location, + Description: result.Description, + }}, nil +} + +// UpdateBox TODO. +func (ep *Endpoints) UpdateBox(ctx context.Context, req api.UpdateBoxRequestObject) (api.UpdateBoxResponseObject, error) { + if req.Bid != req.Body.Id { + return api.UpdateBox406JSONResponse{ + Code: 406, + Message: "Path id not equal to sent id", + }, nil + } + newBox := store.UpdateBoxParams{ + ID: req.Bid, + Location: req.Body.Location, + Description: req.Body.Description, + } + result, err := ep.db.UpdateBox(ctx, newBox) + if err != nil { + log.Printf("error: %+v", err) + return api.UpdateBox507JSONResponse{ + Code: 507, + Message: "Failed to store", + }, nil + } + return api.UpdateBox200JSONResponse{ + BoxJSONResponse: api.BoxJSONResponse{ + Id: result.ID, + Location: result.Location, + Description: result.Description, + }}, nil +} + +// DeleteBox TODO. +func (ep *Endpoints) DeleteBox(ctx context.Context, req api.DeleteBoxRequestObject) (api.DeleteBoxResponseObject, error) { + result, err := ep.db.DeleteBox(ctx, req.Bid) + if err != nil { + log.Printf("error: %+v", err) + return api.DeleteBox404JSONResponse{ + Code: 404, + Message: "Failed to delete", + }, nil + } + return api.DeleteBox200JSONResponse{ + BoxJSONResponse: api.BoxJSONResponse{ + Id: result.ID, + Location: result.Location, + Description: result.Description, + }}, nil +} + +// GetBoxes returns a list of boxes. +func (ep *Endpoints) GetBoxes(ctx context.Context, req api.GetBoxesRequestObject) (api.GetBoxesResponseObject, error) { + var boxes []store.Box + var err error + if req.Params.Filter == nil { + boxes, err = ep.db.GetBoxes(ctx) + } else { + boxes, err = ep.db.GetBoxesWithFilter(ctx, fmt.Sprintf("%%%s%%", *req.Params.Filter)) + } + if err != nil { + log.Printf("error: %+v", err) + return api.GetBoxes500JSONResponse{ + Code: 500, + Message: "Failed to fetch", + }, nil + } + result := make(api.Boxes, len(boxes)) + for i := range boxes { + result[i].Id = boxes[i].ID + result[i].Location = boxes[i].Location + result[i].Description = boxes[i].Description + } + + return api.GetBoxes200JSONResponse{ + BoxesJSONResponse: result, + }, nil +} diff --git a/server/contents.go b/server/contents.go new file mode 100644 index 0000000..f7cb4a2 --- /dev/null +++ b/server/contents.go @@ -0,0 +1,161 @@ +// Package server implements the server. +package server + +import ( + "context" + "database/sql" + "fmt" + "log" + "strings" + + "git.lyda.ie/kevin/boxes/api" + "git.lyda.ie/kevin/boxes/database/store" +) + +func tags2db(tags *[]string) sql.NullString { + if tags == nil { + return sql.NullString{} + } + return sql.NullString{ + String: fmt.Sprintf(",%s,", strings.Join(*tags, ",")), + Valid: true, + } +} + +func db2tags(tags sql.NullString) *[]string { + if tags.Valid { + t := strings.Split(strings.Trim(tags.String, ","), ",") + return &t + } + return nil +} + +// GetContent TODO. +func (ep *Endpoints) GetContent(ctx context.Context, req api.GetContentRequestObject) (api.GetContentResponseObject, error) { + content, err := ep.db.GetContent(ctx, req.Cid) + if err != nil { + log.Printf("error: %+v", err) + return api.GetContent404JSONResponse{ + Code: 404, + Message: "Not found", + }, nil + } + return api.GetContent200JSONResponse{ + ContentJSONResponse: api.ContentJSONResponse{ + Id: content.ID, + Box: content.Box, + Description: content.Description, + Tags: db2tags(content.Tags), + }}, nil +} + +// CreateContent TODO. +func (ep *Endpoints) CreateContent(ctx context.Context, req api.CreateContentRequestObject) (api.CreateContentResponseObject, error) { + if req.Cid != req.Body.Id { + log.Printf("error: %+v != %+v", req.Cid, req.Body) + return api.CreateContent406JSONResponse{ + Code: 406, + Message: "Path id not equal to sent id", + }, nil + } + newContent := store.CreateContentParams{ + ID: req.Cid, + Box: req.Body.Box, + Description: req.Body.Description, + Tags: tags2db(req.Body.Tags), + } + result, err := ep.db.CreateContent(ctx, newContent) + if err != nil { + log.Printf("error: %+v", err) + return api.CreateContent507JSONResponse{ + Code: 507, + Message: "Failed to store", + }, nil + } + return api.CreateContent200JSONResponse{ + ContentJSONResponse: api.ContentJSONResponse{ + Id: result.ID, + Box: result.Box, + Description: result.Description, + Tags: db2tags(result.Tags), + }}, nil +} + +// UpdateContent TODO. +func (ep *Endpoints) UpdateContent(ctx context.Context, req api.UpdateContentRequestObject) (api.UpdateContentResponseObject, error) { + if req.Cid != req.Body.Id { + return api.UpdateContent406JSONResponse{ + Code: 406, + Message: "Path id not equal to sent id", + }, nil + } + newContent := store.UpdateContentParams{ + ID: req.Cid, + Box: req.Body.Box, + Description: req.Body.Description, + Tags: tags2db(req.Body.Tags), + } + result, err := ep.db.UpdateContent(ctx, newContent) + if err != nil { + log.Printf("error: %+v", err) + return api.UpdateContent507JSONResponse{ + Code: 507, + Message: "Failed to store", + }, nil + } + return api.UpdateContent200JSONResponse{ + ContentJSONResponse: api.ContentJSONResponse{ + Id: result.ID, + Box: result.Box, + Description: result.Description, + Tags: db2tags(result.Tags), + }}, nil +} + +// DeleteContent TODO. +func (ep *Endpoints) DeleteContent(ctx context.Context, req api.DeleteContentRequestObject) (api.DeleteContentResponseObject, error) { + result, err := ep.db.DeleteContent(ctx, req.Cid) + if err != nil { + log.Printf("error: %+v", err) + return api.DeleteContent404JSONResponse{ + Code: 404, + Message: "Failed to delete", + }, nil + } + return api.DeleteContent200JSONResponse{ + ContentJSONResponse: api.ContentJSONResponse{ + Id: result.ID, + Box: result.Box, + Description: result.Description, + Tags: db2tags(result.Tags), + }}, nil +} + +// GetContents returns a list of contents. +func (ep *Endpoints) GetContents(ctx context.Context, req api.GetContentsRequestObject) (api.GetContentsResponseObject, error) { + var contents []store.Content + var err error + if req.Params.Filter == nil { + contents, err = ep.db.GetContents(ctx) + } else { + contents, err = ep.db.GetContentsWithFilter(ctx, fmt.Sprintf("%%%s%%", *req.Params.Filter)) + } + if err != nil { + log.Printf("error: %+v", err) + return api.GetContents500JSONResponse{ + Code: 500, + Message: "Failed to fetch", + }, nil + } + result := make(api.Contents, len(contents)) + for i := range contents { + result[i].Id = contents[i].ID + result[i].Box = contents[i].Box + result[i].Description = contents[i].Description + result[i].Tags = db2tags(contents[i].Tags) + } + + return api.GetContents200JSONResponse{ + ContentsJSONResponse: result, + }, nil +} diff --git a/server/endpoints.go b/server/endpoints.go index 8317497..a2fd3d2 100644 --- a/server/endpoints.go +++ b/server/endpoints.go @@ -2,11 +2,8 @@ package server import ( - "context" "database/sql" - "log" - "git.lyda.ie/kevin/boxes/api" "git.lyda.ie/kevin/boxes/database/store" ) @@ -21,175 +18,3 @@ func NewEndpoints(db *sql.DB) *Endpoints { db: *store.New(db), } } - -// GetLocation TODO. -func (ep *Endpoints) GetLocation(ctx context.Context, req api.GetLocationRequestObject) (api.GetLocationResponseObject, error) { - loc, err := ep.db.GetLocation(ctx, req.Lid) - if err != nil { - log.Printf("error: %+v", err) - return api.GetLocation404JSONResponse{ - Code: 404, - Message: "Not found", - }, nil - } - return api.GetLocation200JSONResponse{ - LocationJSONResponse: api.LocationJSONResponse{ - Id: loc.ID, - Description: loc.Description, - }}, nil -} - -// CreateLocation TODO. -func (ep *Endpoints) CreateLocation(ctx context.Context, req api.CreateLocationRequestObject) (api.CreateLocationResponseObject, error) { - if req.Lid != req.Body.Id { - log.Printf("error: %+v != %+v", req.Lid, req.Body) - return api.CreateLocation406JSONResponse{ - Code: 406, - Message: "Path id not equal to sent id", - }, nil - } - newLoc := store.CreateLocationParams{ - ID: req.Lid, - Description: req.Body.Description, - } - result, err := ep.db.CreateLocation(ctx, newLoc) - if err != nil { - log.Printf("error: %+v", err) - return api.CreateLocation507JSONResponse{ - Code: 507, - Message: "Failed to store", - }, nil - } - return api.CreateLocation200JSONResponse{ - LocationJSONResponse: api.LocationJSONResponse{ - Id: result.ID, - Description: result.Description, - }}, nil -} - -// UpdateLocation TODO. -func (ep *Endpoints) UpdateLocation(ctx context.Context, req api.UpdateLocationRequestObject) (api.UpdateLocationResponseObject, error) { - if req.Lid != req.Body.Id { - return api.UpdateLocation406JSONResponse{ - Code: 406, - Message: "Path id not equal to sent id", - }, nil - } - newLoc := store.UpdateLocationParams{ - ID: req.Lid, - Description: req.Body.Description, - } - result, err := ep.db.UpdateLocation(ctx, newLoc) - if err != nil { - log.Printf("error: %+v", err) - return api.UpdateLocation507JSONResponse{ - Code: 507, - Message: "Failed to store", - }, nil - } - return api.UpdateLocation200JSONResponse{ - LocationJSONResponse: api.LocationJSONResponse{ - Id: result.ID, - Description: result.Description, - }}, nil -} - -// DeleteLocation TODO. -func (ep *Endpoints) DeleteLocation(ctx context.Context, req api.DeleteLocationRequestObject) (api.DeleteLocationResponseObject, error) { - result, err := ep.db.DeleteLocation(ctx, req.Lid) - if err != nil { - log.Printf("error: %+v", err) - return api.DeleteLocation404JSONResponse{ - Code: 404, - Message: "Failed to delete", - }, nil - } - return api.DeleteLocation200JSONResponse{ - LocationJSONResponse: api.LocationJSONResponse{ - Id: result.ID, - Description: result.Description, - }}, nil -} - -// GetLocations returns a list of locations. -func (ep *Endpoints) GetLocations(ctx context.Context, req api.GetLocationsRequestObject) (api.GetLocationsResponseObject, error) { - var locs []store.Location - var err error - if req.Params.Filter == nil { - locs, err = ep.db.GetLocations(ctx) - } else { - locs, err = ep.db.GetLocationsWithFilter(ctx, *req.Params.Filter) - } - if err != nil { - log.Printf("error: %+v", err) - return api.GetLocations500JSONResponse{ - Code: 500, - Message: "Failed to fetch", - }, nil - } - result := make(api.Locations, len(locs)) - for i := range locs { - result[i].Id = locs[i].ID - result[i].Description = locs[i].Description - } - - return api.GetLocations200JSONResponse{ - LocationsJSONResponse: result, - }, nil -} - -// GetBox TODO. -func (ep *Endpoints) GetBox(ctx context.Context, req api.GetBoxRequestObject) (api.GetBoxResponseObject, error) { - return api.GetBox200JSONResponse{}, nil -} - -// CreateBox TODO. -func (ep *Endpoints) CreateBox(ctx context.Context, req api.CreateBoxRequestObject) (api.CreateBoxResponseObject, error) { - return api.CreateBox200JSONResponse{}, nil -} - -// UpdateBox TODO. -func (ep *Endpoints) UpdateBox(ctx context.Context, req api.UpdateBoxRequestObject) (api.UpdateBoxResponseObject, error) { - return api.UpdateBox200JSONResponse{}, nil -} - -// DeleteBox TODO. -func (ep *Endpoints) DeleteBox(ctx context.Context, req api.DeleteBoxRequestObject) (api.DeleteBoxResponseObject, error) { - return api.DeleteBox200JSONResponse{}, nil -} - -// GetBoxes returns a list of locations. -func (ep *Endpoints) GetBoxes(ctx context.Context, req api.GetBoxesRequestObject) (api.GetBoxesResponseObject, error) { - boxes := []api.Box{} - return api.GetBoxes200JSONResponse{ - BoxesJSONResponse: boxes, - }, nil -} - -// GetContent TODO. -func (ep *Endpoints) GetContent(ctx context.Context, req api.GetContentRequestObject) (api.GetContentResponseObject, error) { - return api.GetContent200JSONResponse{}, nil -} - -// CreateContent TODO. -func (ep *Endpoints) CreateContent(ctx context.Context, req api.CreateContentRequestObject) (api.CreateContentResponseObject, error) { - return api.CreateContent200JSONResponse{}, nil -} - -// UpdateContent TODO. -func (ep *Endpoints) UpdateContent(ctx context.Context, req api.UpdateContentRequestObject) (api.UpdateContentResponseObject, error) { - return api.UpdateContent200JSONResponse{}, nil -} - -// DeleteContent TODO. -func (ep *Endpoints) DeleteContent(ctx context.Context, req api.DeleteContentRequestObject) (api.DeleteContentResponseObject, error) { - return api.DeleteContent200JSONResponse{}, nil -} - -// GetContents returns a list of locations. -func (ep *Endpoints) GetContents(ctx context.Context, req api.GetContentsRequestObject) (api.GetContentsResponseObject, error) { - content := []api.Content{} - return api.GetContents200JSONResponse{ - ContentsJSONResponse: content, - }, nil -} diff --git a/server/locations.go b/server/locations.go new file mode 100644 index 0000000..b2ef0f2 --- /dev/null +++ b/server/locations.go @@ -0,0 +1,127 @@ +// Package server implements the server. +package server + +import ( + "context" + "fmt" + "log" + + "git.lyda.ie/kevin/boxes/api" + "git.lyda.ie/kevin/boxes/database/store" +) + +// GetLocation TODO. +func (ep *Endpoints) GetLocation(ctx context.Context, req api.GetLocationRequestObject) (api.GetLocationResponseObject, error) { + loc, err := ep.db.GetLocation(ctx, req.Lid) + if err != nil { + log.Printf("error: %+v", err) + return api.GetLocation404JSONResponse{ + Code: 404, + Message: "Not found", + }, nil + } + return api.GetLocation200JSONResponse{ + LocationJSONResponse: api.LocationJSONResponse{ + Id: loc.ID, + Description: loc.Description, + }}, nil +} + +// CreateLocation TODO. +func (ep *Endpoints) CreateLocation(ctx context.Context, req api.CreateLocationRequestObject) (api.CreateLocationResponseObject, error) { + if req.Lid != req.Body.Id { + log.Printf("error: %+v != %+v", req.Lid, req.Body) + return api.CreateLocation406JSONResponse{ + Code: 406, + Message: "Path id not equal to sent id", + }, nil + } + newLoc := store.CreateLocationParams{ + ID: req.Lid, + Description: req.Body.Description, + } + result, err := ep.db.CreateLocation(ctx, newLoc) + if err != nil { + log.Printf("error: %+v", err) + return api.CreateLocation507JSONResponse{ + Code: 507, + Message: "Failed to store", + }, nil + } + return api.CreateLocation200JSONResponse{ + LocationJSONResponse: api.LocationJSONResponse{ + Id: result.ID, + Description: result.Description, + }}, nil +} + +// UpdateLocation TODO. +func (ep *Endpoints) UpdateLocation(ctx context.Context, req api.UpdateLocationRequestObject) (api.UpdateLocationResponseObject, error) { + if req.Lid != req.Body.Id { + return api.UpdateLocation406JSONResponse{ + Code: 406, + Message: "Path id not equal to sent id", + }, nil + } + newLoc := store.UpdateLocationParams{ + ID: req.Lid, + Description: req.Body.Description, + } + result, err := ep.db.UpdateLocation(ctx, newLoc) + if err != nil { + log.Printf("error: %+v", err) + return api.UpdateLocation507JSONResponse{ + Code: 507, + Message: "Failed to store", + }, nil + } + return api.UpdateLocation200JSONResponse{ + LocationJSONResponse: api.LocationJSONResponse{ + Id: result.ID, + Description: result.Description, + }}, nil +} + +// DeleteLocation TODO. +func (ep *Endpoints) DeleteLocation(ctx context.Context, req api.DeleteLocationRequestObject) (api.DeleteLocationResponseObject, error) { + result, err := ep.db.DeleteLocation(ctx, req.Lid) + if err != nil { + log.Printf("error: %+v", err) + return api.DeleteLocation404JSONResponse{ + Code: 404, + Message: "Failed to delete", + }, nil + } + return api.DeleteLocation200JSONResponse{ + LocationJSONResponse: api.LocationJSONResponse{ + Id: result.ID, + Description: result.Description, + }}, nil +} + +// GetLocations returns a list of locations. +func (ep *Endpoints) GetLocations(ctx context.Context, req api.GetLocationsRequestObject) (api.GetLocationsResponseObject, error) { + var locs []store.Location + var err error + if req.Params.Filter == nil { + locs, err = ep.db.GetLocations(ctx) + } else { + locs, err = ep.db.GetLocationsWithFilter(ctx, fmt.Sprintf("%%%s%%", *req.Params.Filter)) + } + if err != nil { + log.Printf("error: %+v", err) + return api.GetLocations500JSONResponse{ + Code: 500, + Message: "Failed to fetch", + }, nil + } + result := make(api.Locations, len(locs)) + for i := range locs { + result[i].Id = locs[i].ID + result[i].Description = locs[i].Description + } + + return api.GetLocations200JSONResponse{ + LocationsJSONResponse: result, + }, nil +} diff --git a/server/server.go b/server/server.go index afaa717..1995215 100644 --- a/server/server.go +++ b/server/server.go @@ -2,12 +2,12 @@ package server import ( + "context" "database/sql" "fmt" // The sqlite db and migration driver. _ "github.com/golang-migrate/migrate/v4/database/sqlite" - _ "modernc.org/sqlite" "git.lyda.ie/kevin/boxes/api" "git.lyda.ie/kevin/boxes/database" @@ -16,6 +16,7 @@ import ( "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/spf13/cobra" + "modernc.org/sqlite" ) // Run starts the metrics and API servers. @@ -31,6 +32,17 @@ func Run(cmd *cobra.Command, _ []string) { e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{})) // Connect and configure the database. + // See https://theitsolutions.io/blog/modernc.org-sqlite-with-go + const pragmas = ` + PRAGMA foreign_keys = ON; +` + ctx := context.TODO() + sqlite.RegisterConnectionHook(func(conn sqlite.ExecQuerierContext, _ string) error { + _, err = conn.ExecContext(ctx, pragmas, nil) + + return err + }) + migrationFS, err := iofs.New(database.MigrationsFS, "migrations") cobra.CheckErr(err) migration, err := migrate.NewWithSourceInstance("iofs", migrationFS, "sqlite://"+dbfile) -- GitLab