diff options
Diffstat (limited to 'internal/storage/sqlite/reader.go')
-rw-r--r-- | internal/storage/sqlite/reader.go | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/internal/storage/sqlite/reader.go b/internal/storage/sqlite/reader.go new file mode 100644 index 0000000..fe5da7e --- /dev/null +++ b/internal/storage/sqlite/reader.go @@ -0,0 +1,99 @@ +package sqlite + +import ( + "database/sql" + "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 + } +} + +func NewReader(dbPath string, log *log.Logger) (r *Reader, err error) { + db, err := openDB(dbPath) + if err != nil { + return nil, errors.WithMessage(err, "could not open SQLite database") + } + + r = &Reader{ + log: log, + db: db, + } + r.queries.getFile, err = r.db.Prepare(` + SELECT + file.content_type, + file.last_modified, + file.etag, + content.body + FROM url + INNER JOIN file + ON file.url_id = url.id + INNER JOIN content + ON content.file_id = file.id + WHERE + url.path = ? + AND + content.encoding = 'identity' + `) + if err != nil { + return nil, errors.WithMessage(err, "preparing select statement") + } + + return r, nil +} + +func (r *Reader) GetFile(filename string) (*storage.File, error) { + file := &storage.File{ + Encodings: make(map[string]*buffer.Buffer, 1), + } + content := []byte{} + var unixTime int64 + err := r.queries.getFile.QueryRow(filename).Scan( + &file.ContentType, + &unixTime, + &file.Etag, + &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["identity"] = buffer.NewBuffer(content) + + return file, nil +} + +// TODO write specialised query +func (r *Reader) CanonicalisePath(path string) (cPath string, differs bool) { + cPath = path + if strings.HasSuffix(path, "/index.html") { + cPath, differs = strings.CutSuffix(path, "index.html") + } else if !strings.HasSuffix(path, "/") { + file, err := r.GetFile(path + "/") + if err != nil { + r.log.Warn("error canonicalising path", "path", path, "error", err) + + return + } + + if file != nil { + cPath, differs = path+"/", true + } + } + + return +} |