Add revision-aware CMS taxonomies and relationships
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// Package cmssqlite stores cms values in an application's SQLite transaction.
|
||||
// Schema installation is explicit. Callers own database opening, migration
|
||||
// versions, authorization and audits. Every mutation must use a caller-owned
|
||||
// transaction, committing its domain change and audit together; never use a
|
||||
// pooled *sql.DB for multi-statement writes. Namespaces isolate application data.
|
||||
package cmssqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"gamertan.com/web/cms"
|
||||
)
|
||||
|
||||
type Queryer interface {
|
||||
QueryContext(context.Context, string, ...any) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...any) *sql.Row
|
||||
}
|
||||
|
||||
// Reader may use a database or read transaction. Writers below require *sql.Tx.
|
||||
type Reader struct {
|
||||
db Queryer
|
||||
scope string
|
||||
}
|
||||
|
||||
func New(db Queryer, scope string) (*Reader, error) {
|
||||
if db == nil || !cms.ValidID(scope) {
|
||||
return nil, cms.ErrInvalid
|
||||
}
|
||||
return &Reader{db: db, scope: scope}, nil
|
||||
}
|
||||
|
||||
// CreateSchema must be called from the application's explicit migration.
|
||||
// It never changes an existing publishing schema or starts a transaction.
|
||||
func CreateSchema(ctx context.Context, tx *sql.Tx) error {
|
||||
for _, statement := range []string{
|
||||
`CREATE TABLE IF NOT EXISTS gwf_cms_taxonomies (scope TEXT NOT NULL,id TEXT NOT NULL,slug TEXT NOT NULL,name TEXT NOT NULL,description TEXT NOT NULL,revision INTEGER NOT NULL CHECK(revision>0),active INTEGER NOT NULL CHECK(active IN (0,1)),PRIMARY KEY(scope,id),UNIQUE(scope,slug))`,
|
||||
`CREATE TABLE IF NOT EXISTS gwf_cms_terms (scope TEXT NOT NULL,id TEXT NOT NULL,taxonomy_id TEXT NOT NULL,slug TEXT NOT NULL,name TEXT NOT NULL,description TEXT NOT NULL,revision INTEGER NOT NULL CHECK(revision>0),active INTEGER NOT NULL CHECK(active IN (0,1)),PRIMARY KEY(scope,id),UNIQUE(scope,taxonomy_id,slug),FOREIGN KEY(scope,taxonomy_id) REFERENCES gwf_cms_taxonomies(scope,id))`,
|
||||
`CREATE TABLE IF NOT EXISTS gwf_cms_term_slugs (scope TEXT NOT NULL,taxonomy_id TEXT NOT NULL,slug TEXT NOT NULL,term_id TEXT NOT NULL,PRIMARY KEY(scope,taxonomy_id,slug),FOREIGN KEY(scope,term_id) REFERENCES gwf_cms_terms(scope,id))`,
|
||||
`CREATE TABLE IF NOT EXISTS gwf_cms_resources (scope TEXT NOT NULL,kind TEXT NOT NULL,id TEXT NOT NULL,published_revision INTEGER NOT NULL DEFAULT 0 CHECK(published_revision>=0),PRIMARY KEY(scope,kind,id))`,
|
||||
`CREATE TABLE IF NOT EXISTS gwf_cms_associations (scope TEXT NOT NULL,kind TEXT NOT NULL,id TEXT NOT NULL,revision INTEGER NOT NULL CHECK(revision>0),document TEXT NOT NULL,PRIMARY KEY(scope,kind,id,revision),FOREIGN KEY(scope,kind,id) REFERENCES gwf_cms_resources(scope,kind,id))`,
|
||||
`CREATE TABLE IF NOT EXISTS gwf_cms_memberships (scope TEXT NOT NULL,kind TEXT NOT NULL,id TEXT NOT NULL,revision INTEGER NOT NULL,term_id TEXT NOT NULL,PRIMARY KEY(scope,kind,id,revision,term_id),FOREIGN KEY(scope,kind,id,revision) REFERENCES gwf_cms_associations(scope,kind,id,revision),FOREIGN KEY(scope,term_id) REFERENCES gwf_cms_terms(scope,id))`,
|
||||
`CREATE INDEX IF NOT EXISTS gwf_cms_memberships_term ON gwf_cms_memberships(scope,term_id,kind,id,revision)`,
|
||||
`CREATE TABLE IF NOT EXISTS gwf_cms_links (scope TEXT NOT NULL,kind TEXT NOT NULL,id TEXT NOT NULL,revision INTEGER NOT NULL,target_kind TEXT NOT NULL,target_id TEXT NOT NULL,PRIMARY KEY(scope,kind,id,revision,target_kind,target_id),FOREIGN KEY(scope,kind,id,revision) REFERENCES gwf_cms_associations(scope,kind,id,revision))`,
|
||||
`CREATE INDEX IF NOT EXISTS gwf_cms_links_target ON gwf_cms_links(scope,target_kind,target_id,kind,id,revision)`,
|
||||
} {
|
||||
if _, err := tx.ExecContext(ctx, statement); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user