switch to sqlite
1 file changed, 127 insertions(+), 0 deletions(-)
changed files
A internal/storage/sqlite/reader.go
@@ -0,0 +1,127 @@ +package sqlite + +import ( + "database/sql" + "io" + "strings" + "time" + + "gitlab.com/tozd/go/errors" + "go.alanpearce.eu/website/internal/buffer" + "go.alanpearce.eu/website/internal/storage" + "go.alanpearce.eu/x/log" +) + +type Reader struct { + db *sql.DB + log *log.Logger + queries struct { + getFile *sql.Stmt + checkPath *sql.Stmt + } +} + +func NewReader(db *sql.DB, log *log.Logger) (r *Reader, err error) { + r = &Reader{ + log: log, + db: db, + } + r.queries.getFile, err = r.db.Prepare(` + SELECT + file.content_type, + file.last_modified, + file.etag, + content.encoding, + content.body + FROM url + INNER JOIN file + USING (url_id) + INNER JOIN content + USING (file_id) + WHERE + url.path = ? + `) + if err != nil { + return nil, errors.WithMessage(err, "preparing select statement") + } + + r.queries.checkPath, err = r.db.Prepare(` + SELECT EXISTS( + SELECT 1 + FROM url + WHERE path = ? + ) AS differs +`) + if err != nil { + return nil, errors.WithMessage(err, "preparing check path statement") + } + + return r, nil +} + +func (r *Reader) GetFile(filename string) (*storage.File, error) { + file := &storage.File{ + Encodings: make(map[string]io.ReadSeeker, 1), + } + var unixTime int64 + var encoding string + var content []byte + rows, err := r.queries.getFile.Query(filename) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + + return nil, errors.WithMessage(err, "querying database") + } + + for rows.Next() { + err = rows.Scan( + &file.ContentType, + &unixTime, + &file.Etag, + &encoding, + &content, + ) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + + return nil, errors.WithMessage(err, "querying database") + } + + file.LastModified = time.Unix(unixTime, 0) + file.Encodings[encoding] = buffer.NewBuffer(content) + } + + return file, nil +} + +func (r *Reader) CanonicalisePath(path string) (cPath string, differs bool) { + cPath = path + switch { + case path == "/": + differs = false + case strings.HasSuffix(path, "/index.html"): + cPath, differs = strings.CutSuffix(path, "index.html") + case !strings.HasSuffix(path, "/"): + cPath += "/" + err := r.queries.checkPath.QueryRow(cPath).Scan(&differs) + if err != nil { + r.log.Warn("error canonicalising path", "path", path, "error", err) + + return + } + case strings.HasSuffix(path, "/"): + cPath = strings.TrimSuffix(path, "/") + err := r.queries.checkPath.QueryRow(cPath).Scan(&differs) + if err != nil { + r.log.Warn("error canonicalising path", "path", path, "error", err) + + return + } + } + + return +}