From 38aa274859f16b5c3385183cd5c666533db8afc9 Mon Sep 17 00:00:00 2001 From: Sandesh Gade Date: Sat, 8 Nov 2025 17:53:07 -0500 Subject: [PATCH] add postgres support --- README.md | 8 ++- go.mod | 10 +++- go.sum | 56 +++++++++++++++++- internal/postgres/db.go | 32 +++++++++++ internal/postgres/models.go | 17 ++++++ internal/postgres/queries.sql | 14 +++++ internal/postgres/queries.sql.go | 73 ++++++++++++++++++++++++ internal/postgres/schema.go | 8 +++ internal/postgres/schema.sql | 7 +++ internal/sqlite/{source.go => schema.go} | 0 postgres.go | 48 ++++++++++++++++ sqlc.yaml | 8 +++ sqlite.go | 26 +-------- transport.go | 6 +- transport_test.go | 17 +++++- 15 files changed, 297 insertions(+), 33 deletions(-) create mode 100644 internal/postgres/db.go create mode 100644 internal/postgres/models.go create mode 100644 internal/postgres/queries.sql create mode 100644 internal/postgres/queries.sql.go create mode 100644 internal/postgres/schema.go create mode 100644 internal/postgres/schema.sql rename internal/sqlite/{source.go => schema.go} (100%) create mode 100644 postgres.go diff --git a/README.md b/README.md index 158f560..3ecfb33 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,14 @@ The implementation currently uses a very basic hashing mechanism to create a sig ## Todo +- [x] Basic Cache Invalidation support +- [ ] Add `postgres` as an alternative source +- [ ] Improve test coverage +- [ ] Add `pgxpool` support for `postgres` source - [ ] Custom caching strategy based on HTTP response status codes - [ ] Explore parsing [Cache Control headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control) for request-level control - [ ] Bring your own HTTP request hasher -- [x] Basic Cache Invalidation support - [ ] Configurable Cache Invalidation support -- [ ] Improve test coverage - [ ] Add build/contribution guide to readme +- [ ] Support returning HTTP headers in cached response +- [ ] Improve documentation diff --git a/go.mod b/go.mod index 73ecf7b..f429922 100644 --- a/go.mod +++ b/go.mod @@ -2,16 +2,24 @@ module github.com/cyberbeast/httpcache go 1.25.3 +require ( + github.com/jackc/pgx/v5 v5.7.6 + modernc.org/sqlite v1.40.0 +) + require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/crypto v0.37.0 // indirect golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.24.0 // indirect modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect - modernc.org/sqlite v1.39.1 // indirect ) diff --git a/go.sum b/go.sum index 7aee46f..08e3e85 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,75 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk= +github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= +modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= +modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q= +modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= +modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= -modernc.org/sqlite v1.39.1 h1:H+/wGFzuSCIEVCvXYVHX5RQglwhMOvtHSv+VtidL2r4= -modernc.org/sqlite v1.39.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.40.0 h1:bNWEDlYhNPAUdUdBzjAvn8icAs/2gaKlj4vM+tQ6KdQ= +modernc.org/sqlite v1.40.0/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/internal/postgres/db.go b/internal/postgres/db.go new file mode 100644 index 0000000..8737077 --- /dev/null +++ b/internal/postgres/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package postgres + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/postgres/models.go b/internal/postgres/models.go new file mode 100644 index 0000000..dea728b --- /dev/null +++ b/internal/postgres/models.go @@ -0,0 +1,17 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 + +package postgres + +import ( + "github.com/jackc/pgx/v5/pgtype" +) + +type Response struct { + ReqHash string + Body pgtype.Text + Headers pgtype.Text + StatusCode pgtype.Int4 + UpdatedAt pgtype.Timestamptz +} diff --git a/internal/postgres/queries.sql b/internal/postgres/queries.sql new file mode 100644 index 0000000..66e1729 --- /dev/null +++ b/internal/postgres/queries.sql @@ -0,0 +1,14 @@ +-- name: GetResponse :one +SELECT * FROM responses WHERE req_hash = $1 LIMIT 1; + +-- name: CacheResponse :one +INSERT INTO responses ( + req_hash, body, headers, status_code +) +VALUES ( + $1, $2, $3, $4 +) +RETURNING *; + +-- name: DeleteAllResponses :exec +DELETE FROM responses; \ No newline at end of file diff --git a/internal/postgres/queries.sql.go b/internal/postgres/queries.sql.go new file mode 100644 index 0000000..4ece11b --- /dev/null +++ b/internal/postgres/queries.sql.go @@ -0,0 +1,73 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.30.0 +// source: queries.sql + +package postgres + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const cacheResponse = `-- name: CacheResponse :one +INSERT INTO responses ( + req_hash, body, headers, status_code +) +VALUES ( + $1, $2, $3, $4 +) +RETURNING req_hash, body, headers, status_code, updated_at +` + +type CacheResponseParams struct { + ReqHash string + Body pgtype.Text + Headers pgtype.Text + StatusCode pgtype.Int4 +} + +func (q *Queries) CacheResponse(ctx context.Context, arg CacheResponseParams) (Response, error) { + row := q.db.QueryRow(ctx, cacheResponse, + arg.ReqHash, + arg.Body, + arg.Headers, + arg.StatusCode, + ) + var i Response + err := row.Scan( + &i.ReqHash, + &i.Body, + &i.Headers, + &i.StatusCode, + &i.UpdatedAt, + ) + return i, err +} + +const deleteAllResponses = `-- name: DeleteAllResponses :exec +DELETE FROM responses +` + +func (q *Queries) DeleteAllResponses(ctx context.Context) error { + _, err := q.db.Exec(ctx, deleteAllResponses) + return err +} + +const getResponse = `-- name: GetResponse :one +SELECT req_hash, body, headers, status_code, updated_at FROM responses WHERE req_hash = $1 LIMIT 1 +` + +func (q *Queries) GetResponse(ctx context.Context, reqHash string) (Response, error) { + row := q.db.QueryRow(ctx, getResponse, reqHash) + var i Response + err := row.Scan( + &i.ReqHash, + &i.Body, + &i.Headers, + &i.StatusCode, + &i.UpdatedAt, + ) + return i, err +} diff --git a/internal/postgres/schema.go b/internal/postgres/schema.go new file mode 100644 index 0000000..fafc5d2 --- /dev/null +++ b/internal/postgres/schema.go @@ -0,0 +1,8 @@ +package postgres + +import ( + _ "embed" +) + +//go:embed schema.sql +var Schema string diff --git a/internal/postgres/schema.sql b/internal/postgres/schema.sql new file mode 100644 index 0000000..7688a41 --- /dev/null +++ b/internal/postgres/schema.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS responses ( + req_hash TEXT PRIMARY KEY, + body TEXT, + headers TEXT, + status_code INT, + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); diff --git a/internal/sqlite/source.go b/internal/sqlite/schema.go similarity index 100% rename from internal/sqlite/source.go rename to internal/sqlite/schema.go diff --git a/postgres.go b/postgres.go new file mode 100644 index 0000000..adf4ba3 --- /dev/null +++ b/postgres.go @@ -0,0 +1,48 @@ +package httpcache + +import ( + "context" + + "github.com/cyberbeast/httpcache/internal/postgres" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" +) + +type pgstore struct{ queries *postgres.Queries } + +func (s *pgstore) CacheResponse(ctx context.Context, arg Params) (Response, error) { + return wrapPostgresResponse(s.queries.CacheResponse(ctx, postgres.CacheResponseParams{ + ReqHash: arg.ReqHash, + Body: pgtype.Text{String: arg.Body, Valid: true}, + Headers: pgtype.Text{String: arg.Headers, Valid: true}, + StatusCode: pgtype.Int4{Int32: int32(arg.StatusCode), Valid: true}, + })) +} + +func (s *pgstore) DeleteAllResponses(ctx context.Context) error { + return s.queries.DeleteAllResponses(ctx) +} + +func (s *pgstore) GetResponse(ctx context.Context, reqHash string) (Response, error) { + return wrapPostgresResponse(s.queries.GetResponse(ctx, reqHash)) +} + +func wrapPostgresResponse(res postgres.Response, err error) (Response, error) { + return Response{ + ReqHash: res.ReqHash, + Body: res.Body.String, + Headers: res.Headers.String, + StatusCode: int(res.StatusCode.Int32), + UpdatedAt: res.UpdatedAt.Time.String(), + }, err +} + +type PostgresSource struct{ *pgx.Conn } + +func (p PostgresSource) Init(ctx context.Context) (Querier, error) { + if _, err := p.Exec(ctx, postgres.Schema); err != nil { + return nil, err + } + + return &pgstore{queries: postgres.New(p)}, nil +} diff --git a/sqlc.yaml b/sqlc.yaml index d588f69..ac6a6f9 100644 --- a/sqlc.yaml +++ b/sqlc.yaml @@ -7,3 +7,11 @@ sql: go: package: sqlite out: ./internal/sqlite + - engine: postgresql + schema: ./internal/postgres/schema.sql + queries: ./internal/postgres/queries.sql + gen: + go: + package: postgres + out: ./internal/postgres + sql_package: pgx/v5 diff --git a/sqlite.go b/sqlite.go index 121fdd1..056562b 100644 --- a/sqlite.go +++ b/sqlite.go @@ -4,10 +4,8 @@ import ( "context" "database/sql" "fmt" - "strings" "github.com/cyberbeast/httpcache/internal/sqlite" - _ "modernc.org/sqlite" ) type sqliteStore struct{ queries *sqlite.Queries } @@ -39,30 +37,12 @@ func wrapSQLiteResponse(res sqlite.Response, err error) (Response, error) { }, err } -const filePrefix = "file://" - -type SQLiteSource string - -func (s SQLiteSource) name() string { return "sqlite" } - -func (s SQLiteSource) filepath() string { - file := string(s) - if !strings.HasPrefix(file, filePrefix) { - file = filePrefix + file - } - - return file -} +type SQLiteSource struct{ *sql.DB } func (s SQLiteSource) Init(ctx context.Context) (Querier, error) { - db, err := sql.Open(s.name(), s.filepath()) - if err != nil { - return nil, fmt.Errorf("opening db: %w", err) - } - - if _, err := db.ExecContext(ctx, sqlite.Schema); err != nil { + if _, err := s.ExecContext(ctx, sqlite.Schema); err != nil { return nil, fmt.Errorf("creating db schema: %w", err) } - return &sqliteStore{queries: sqlite.New(db)}, nil + return &sqliteStore{queries: sqlite.New(s)}, nil } diff --git a/transport.go b/transport.go index 6d4a993..c1c6591 100644 --- a/transport.go +++ b/transport.go @@ -8,7 +8,7 @@ import ( "strings" ) -type Cache interface { +type Source interface { Init(ctx context.Context) (Querier, error) } @@ -18,8 +18,8 @@ type Querier interface { DeleteAllResponses(ctx context.Context) error } -func NewTransport(ctx context.Context, cache Cache, rt http.RoundTripper) (*cachedTransport, error) { - store, err := cache.Init(ctx) +func NewTransport(ctx context.Context, src Source, rt http.RoundTripper) (*cachedTransport, error) { + store, err := src.Init(ctx) if err != nil { return nil, err } diff --git a/transport_test.go b/transport_test.go index d90bb7e..ee5506d 100644 --- a/transport_test.go +++ b/transport_test.go @@ -1,12 +1,15 @@ package httpcache import ( + "database/sql" "io" "net/http" "net/http/httptest" "path" "testing" "time" + + _ "modernc.org/sqlite" ) func TestTransport(t *testing.T) { @@ -14,7 +17,12 @@ func TestTransport(t *testing.T) { srv := httptest.NewServer(delayedResponse(delay)) defer srv.Close() - tr, err := NewTransport(t.Context(), SQLiteSource(path.Join(t.TempDir(), "temp.db")), nil) + db, err := sql.Open("sqlite", path.Join("file://", t.TempDir(), "temp.db")) + if err != nil { + t.Fatalf("creating sqlite db: %v", err) + } + + tr, err := NewTransport(t.Context(), SQLiteSource{db}, nil) if err != nil { t.Fatalf("couldn't initialize transport for test: %v", err) } @@ -43,7 +51,12 @@ func TestTransportInvalidateAllResponses(t *testing.T) { srv := httptest.NewServer(delayedResponse(delay)) defer srv.Close() - tr, err := NewTransport(t.Context(), SQLiteSource(path.Join(t.TempDir(), "temp.db")), nil) + db, err := sql.Open("sqlite", path.Join("file://", t.TempDir(), "temp.db")) + if err != nil { + t.Fatalf("creating sqlite db: %v", err) + } + + tr, err := NewTransport(t.Context(), SQLiteSource{db}, nil) if err != nil { t.Fatalf("couldn't initialize transport for test: %v", err) }