Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
7f88ca7
feat: save documentation info to SQLite databse
david-christiansen Jan 16, 2026
9272ece
Try multiple DBs
david-christiansen Jan 20, 2026
418fa51
Try not generating equations in DB
david-christiansen Jan 20, 2026
76667ea
try getting Mathlib cache earlier
david-christiansen Jan 20, 2026
e429f8e
It seems to build modules and not just make docs. Try this.
david-christiansen Jan 20, 2026
c90bd81
Revert "Try not generating equations in DB"
david-christiansen Jan 20, 2026
e1d2a8b
Revert "Try multiple DBs"
david-christiansen Jan 20, 2026
1d77c52
feat: serialize Verso docstrings
david-christiansen Jan 26, 2026
ec4cf3e
chore: render code to HTML via RenderedCode
david-christiansen Jan 27, 2026
9489cfd
refactor: save RenderedCode instead of CodeWithInfos
david-christiansen Jan 27, 2026
931fd6a
chore: check differences between HTML output
david-christiansen Jan 30, 2026
9af0293
feat: save hashes for material in DB
david-christiansen Jan 30, 2026
0160e76
chore: print timing for html from db
david-christiansen Jan 30, 2026
5bd12d0
feat: try parallel generation from db
david-christiansen Jan 30, 2026
b9c77db
chore: use database-driven HTML in benchmark
david-christiansen Jan 30, 2026
c6f2804
Merge remote-tracking branch 'upstream/main' into db
david-christiansen Jan 30, 2026
61cb408
chore: remove legacy HTML output
david-christiansen Feb 2, 2026
8409ddb
chore: dead code removal
david-christiansen Feb 2, 2026
af8611d
chore: better naming
david-christiansen Feb 2, 2026
f45fd31
fix: update build command in workflow
david-christiansen Feb 2, 2026
c169a17
fix: don't put database in HTML dir
david-christiansen Feb 2, 2026
569cd63
fix: build docs for dependencies' contents
david-christiansen Feb 2, 2026
fa6ae51
fix: get an updated Plausible to avoid version compat issue in benchmark
david-christiansen Feb 2, 2026
8cb1804
Merge remote-tracking branch 'upstream/main' into db
david-christiansen Feb 3, 2026
e216fd2
feat: detect mismatched schemas
david-christiansen Feb 3, 2026
8f11577
fix: make facets work as before
david-christiansen Feb 3, 2026
0f42d49
Revert CI change
david-christiansen Feb 3, 2026
8d513bf
fix core deps
david-christiansen Feb 3, 2026
0ad430a
group html jobs
david-christiansen Feb 3, 2026
58628b3
bump timeout values for huge builds with db write contention
david-christiansen Feb 3, 2026
b519df8
fix: return file lists again
david-christiansen Feb 4, 2026
ee4d236
Files again
david-christiansen Feb 4, 2026
64ced84
chore: try WITHOUT ROWID
david-christiansen Feb 4, 2026
75e23c6
Revert "chore: try WITHOUT ROWID"
david-christiansen Feb 4, 2026
52cd13e
try turning off synchronous writes
david-christiansen Feb 4, 2026
2e5f95b
simplify handling of equations
david-christiansen Feb 4, 2026
8fdc1ce
Batch up transactions for core docs
david-christiansen Feb 4, 2026
28f670b
fix batching and use subarrays for them
david-christiansen Feb 4, 2026
bc3e727
timing prints
david-christiansen Feb 4, 2026
d9e7403
try just building Mathlib DB
david-christiansen Feb 4, 2026
21e4d9b
Chunk up HTML generation
david-christiansen Feb 4, 2026
48817ad
Revert "try just building Mathlib DB"
david-christiansen Feb 4, 2026
57be658
Try single-threaded HTML output
david-christiansen Feb 4, 2026
4e30ff2
Revert "Try single-threaded HTML output"
david-christiansen Feb 4, 2026
f47fbb4
Revert "timing prints"
david-christiansen Feb 4, 2026
5913631
Remove timing print code
david-christiansen Feb 4, 2026
3dc6514
Start cleanup
david-christiansen Feb 6, 2026
55f22f3
chore: refactor/reorganize for clarity
david-christiansen Feb 7, 2026
f2ad064
wip handlers
david-christiansen Feb 9, 2026
bd98bae
chore: use upstream instances
david-christiansen Feb 10, 2026
47456ac
Merge remote-tracking branch 'upstream/main' into db
david-christiansen Feb 10, 2026
d13ca31
fix: actually chunk contents
david-christiansen Feb 10, 2026
fc484e7
Merge remote-tracking branch 'upstream/main' into db
david-christiansen Feb 10, 2026
b645b4d
fix: serialization
david-christiansen Feb 10, 2026
5e9aed2
chore: cleanups
david-christiansen Feb 10, 2026
8a025f1
chore: use zstd for benchmark-produced data
david-christiansen Feb 10, 2026
cafaf11
Revert "chore: use zstd for benchmark-produced data"
david-christiansen Feb 10, 2026
8dc6c36
Reapply "chore: use zstd for benchmark-produced data"
david-christiansen Feb 10, 2026
6d413a1
Try bigger chunks
david-christiansen Feb 10, 2026
f1d4513
Don't deserialize long equations
david-christiansen Feb 10, 2026
5fdf9c4
Don't even save long equations
david-christiansen Feb 10, 2026
f3a89f7
Less copying in escape
david-christiansen Feb 10, 2026
5042ed1
Revert "Less copying in escape"
david-christiansen Feb 10, 2026
7c939bd
experiment: emit HTML directly rather than allocating trees and strings
david-christiansen Feb 11, 2026
5e87fd8
Informative exceptions
david-christiansen Feb 11, 2026
76baef3
DB simplifications
david-christiansen Feb 11, 2026
a706e59
Revert "experiment: emit HTML directly rather than allocating trees a…
david-christiansen Feb 11, 2026
9964780
Merge remote-tracking branch 'upstream/main' into db
david-christiansen Feb 11, 2026
a468da6
Attempt to optimize structure reading
david-christiansen Feb 11, 2026
3c25ecb
fix: share DB in tasks
david-christiansen Feb 11, 2026
3c848f2
Single-pass string escape
david-christiansen Feb 11, 2026
4ff68a8
Don't round-trip index to/from disk
david-christiansen Feb 11, 2026
476d604
Do round trip those that didn't just get built
david-christiansen Feb 11, 2026
5550f29
Upload non-corrupted db after bench
david-christiansen Feb 11, 2026
236977d
Save positions as ints
david-christiansen Feb 11, 2026
6062686
Try synchronous mode to see performance impact
david-christiansen Feb 11, 2026
c093b63
Match prior ordering
david-christiansen Feb 11, 2026
88a29d9
fix: always add core docs to HTML output
david-christiansen Feb 11, 2026
2850349
chore: eliminate JSON trip and fix ordering of tactics
david-christiansen Feb 11, 2026
18a4266
Slight increase in eqns robustness
david-christiansen Feb 11, 2026
f7fd765
fix: markdown postprocessing
david-christiansen Feb 12, 2026
bfac47f
fix: only use rendered decls as link targets
david-christiansen Feb 16, 2026
d74c3b3
fix: only link to rendered names
david-christiansen Feb 16, 2026
188f793
Revert "fix: only link to rendered names"
david-christiansen Feb 16, 2026
bad1961
Alternate private name approach
david-christiansen Feb 16, 2026
d2293c7
Revert "fix: only use rendered decls as link targets"
david-christiansen Feb 16, 2026
7136299
fix: don't attempt to auto-link private names
david-christiansen Feb 16, 2026
52bd09d
fix: link targets for parent projections
david-christiansen Feb 16, 2026
3ac4817
better linking
david-christiansen Feb 16, 2026
c95d8b0
Revert "better linking"
david-christiansen Feb 16, 2026
8052748
eliminator links
david-christiansen Feb 16, 2026
edae855
mdata
david-christiansen Feb 17, 2026
167bb2c
Inherited field IDs
david-christiansen Feb 17, 2026
2019832
better projection ids
david-christiansen Feb 18, 2026
c378c39
bibliography pseudo-elem
david-christiansen Feb 18, 2026
b7df555
fix: only rendered items in index
david-christiansen Feb 18, 2026
ea23812
Updated compare script
david-christiansen Feb 18, 2026
1b90817
Merge remote-tracking branch 'upstream/main' into db
david-christiansen Feb 18, 2026
3a20c17
More informative compare script
david-christiansen Feb 19, 2026
c08bf78
Improve index
david-christiansen Feb 19, 2026
07bdad4
better compare
david-christiansen Feb 19, 2026
eeb8074
Small improvements
david-christiansen Feb 19, 2026
173209f
Defensively protect write statements with a mutex
david-christiansen Feb 19, 2026
ded9698
Refactor readdb for parallel structure
david-christiansen Feb 19, 2026
beb37c1
Comments
david-christiansen Feb 19, 2026
06dfc9d
delete unused scripts
david-christiansen Feb 19, 2026
d045303
Proofreading
david-christiansen Feb 20, 2026
9eac515
doc: more informative comment
david-christiansen Feb 20, 2026
77b157f
chore: update comment
david-christiansen Feb 20, 2026
91b4138
chore: add benchmark line tracking documentation database size
david-christiansen Feb 20, 2026
110c073
Update lakefile.lean
david-christiansen Feb 23, 2026
bb0b496
chore: remove useless mapM and add comments
david-christiansen Feb 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DocGen4.lean
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ Authors: Henrik Böving
import DocGen4.Process
import DocGen4.Load
import DocGen4.Output
import DocGen4.DB
663 changes: 663 additions & 0 deletions DocGen4/DB.lean

Large diffs are not rendered by default.

698 changes: 698 additions & 0 deletions DocGen4/DB/Read.lean

Large diffs are not rendered by default.

378 changes: 378 additions & 0 deletions DocGen4/DB/Schema.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,378 @@
/-
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: David Thrane Christiansen
-/
import DocGen4.RenderedCode
import SQLite

/-!
# Database Schema and Initialization

Defines the SQLite DDL (table definitions) and handles database creation, including schema
versioning. The schema is versioned by two hashes:
* The _DDL hash_ detects changes to table definitions (column additions, new tables, etc.).
* The _type hash_ detects changes to Lean types that are serialized as blobs in the database (e.g.,
`RenderedCode`, `RenderedCode.Tag`). It is computed at compile time via `inductiveRepr!`.

If either hash doesn't match, the database is rejected with an error message asking the user to
rebuild. This prevents some silent corruption resulting from reading blobs with a stale
deserializer. Note that changes to the serialization procedures that don't change the datatypes will
not invalidate the hashes, so this measure is not perfect; however, these instances are typically
derived, so they should follow the structure of the type.
-/

namespace DocGen4.DB

open Lean in
/--
Extracts a deterministic string representation of an inductive type, which is used to invalidate
database schemas in which blobs implicitly depend on serializations of datatypes. Includes
constructor names and their types.
-/
private def inductiveRepr (env : Environment) (name : Name) : String := Id.run do
let some (.inductInfo info) := env.find? name | return s!"not found: {name}"
let mut s := s!"inductive {name} : {info.type}\n"
for ctor in info.ctors do
let some (.ctorInfo ctorInfo) := env.find? ctor | continue
let ctorName := ctor.replacePrefix name .anonymous
s := s ++ s!" | {ctorName} : {ctorInfo.type}\n"
return s

namespace Internals
open Lean Elab Term in
/--
Gets a string representation of inductive type definitions, computed at compile time.
-/
scoped elab "inductiveRepr![" types:ident,* "]" : term => do
let env ← getEnv
let mut reprs : Array String := #[]
for type in types.getElems do
let name ← resolveGlobalConstNoOverload type
reprs := reprs.push (inductiveRepr env name)
return .lit (.strVal (String.intercalate "\n" reprs.toList))
end Internals

open Internals in
open Lean.Widget in
/--
The datatypes that are serialized to the database. If they change, then the database should be
rebuilt.
-/
def serializedCodeTypeDefs : String :=
inductiveRepr![
SortFormer,
RenderedCode.Tag,
TaggedText
]

def getDb (dbFile : System.FilePath) : IO SQLite := do
-- SQLite atomically creates the DB file, and the schema and journal settings here are applied
-- idempotently. This avoids DB creation race conditions. A very long busy timeout is used because
-- the analysis phase spawns many, many processes, each of which waits on a transaction lock. In
-- practice, timeouts of up to a minute caused intermittent problems when building Mathlib docs on
-- a fast multicore machine, so 30 is very conservative.
let db ← SQLite.openWith dbFile .readWriteCreate
db.exec "PRAGMA busy_timeout = 1800000" -- 30 minutes
db.exec "PRAGMA journal_mode = WAL"
db.exec "PRAGMA foreign_keys = ON"
try
db.transaction (db.exec ddl)
catch
| e =>
throw <| .userError s!"Exception while creating schema: {e}"
-- Check schema version via DDL hash and type definition hash
let ddlHash := toString ddl.hash
let typeHash := toString serializedCodeTypeDefs.hash
let stmt ← db.prepare "SELECT key, value FROM schema_meta"
let mut storedDdlHash : Option String := none
let mut storedTypeHash : Option String := none
while ← stmt.step do
let key ← stmt.columnText 0
let value ← stmt.columnText 1
if key == "ddl_hash" then storedDdlHash := some value
if key == "type_hash" then storedTypeHash := some value
match storedDdlHash, storedTypeHash with
| none, none =>
-- New database, store the hashes
db.exec s!"INSERT INTO schema_meta (key, value) VALUES ('ddl_hash', '{ddlHash}')"
db.exec s!"INSERT INTO schema_meta (key, value) VALUES ('type_hash', '{typeHash}')"
| some stored, _ =>
if stored != ddlHash then
throw <| .userError s!"Database schema is outdated (DDL hash mismatch). Run `lake clean` or delete '{dbFile}' and rebuild."
match storedTypeHash with
| none =>
-- Older DB without type hash, add it
db.exec s!"INSERT INTO schema_meta (key, value) VALUES ('type_hash', '{typeHash}')"
| some storedType =>
if storedType != typeHash then
throw <| .userError s!"Database schema is outdated (serialized type definitions changed). Run `lake clean` or delete '{dbFile}' and rebuild."
| none, some _ => -- Shouldn't happen, but handle gracefully
db.exec s!"INSERT INTO schema_meta (key, value) VALUES ('ddl_hash', '{ddlHash}')"
return db
where
ddl :=
r#"
PRAGMA journal_mode = WAL;

-- Modules table
CREATE TABLE IF NOT EXISTS modules (
name TEXT PRIMARY KEY,
source_url TEXT
);

-- Direct imports
CREATE TABLE IF NOT EXISTS module_imports (
importer TEXT NOT NULL,
imported TEXT NOT NULL,
PRIMARY KEY (importer, imported),
FOREIGN KEY (importer) REFERENCES modules(name) ON DELETE CASCADE
-- There's no
-- FOREIGN KEY (imported) REFERENCES modules(name)
-- because docs are built incrementally.
);

-- Index for reverse queries: "what imports this module?"
CREATE INDEX IF NOT EXISTS idx_module_imports_imported ON module_imports(imported);

CREATE TABLE IF NOT EXISTS declaration_ranges (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
start_line INTEGER NOT NULL,
start_column INTEGER NOT NULL,
start_utf16 INTEGER NOT NULL,
end_line INTEGER NOT NULL,
end_column INTEGER NOT NULL,
end_utf16 INTEGER NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name) REFERENCES modules(name) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS declaration_markdown_docstrings (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
text TEXT NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name) REFERENCES modules(name) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS module_docs_markdown (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
text TEXT NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name) REFERENCES modules(name) ON DELETE CASCADE
);

-- TODO: Add module_docs_verso table for Lean.VersoModuleDocs.Snippet

CREATE TABLE IF NOT EXISTS declaration_verso_docstrings (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
content BLOB NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name) REFERENCES modules(name) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS name_info (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
kind TEXT,
name TEXT NOT NULL,
type BLOB NOT NULL,
sorried INTEGER NOT NULL,
render INTEGER NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name) REFERENCES modules(name) ON DELETE CASCADE
);

-- Index for lookups by declaration name (e.g. structure field projection lookups)
CREATE INDEX IF NOT EXISTS idx_name_info_name ON name_info(name);

CREATE TABLE IF NOT EXISTS axioms (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
is_unsafe INTEGER NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

-- Internal names (like recursors) that aren't rendered but should link to a rendered declaration
CREATE TABLE IF NOT EXISTS internal_names (
name TEXT NOT NULL PRIMARY KEY,
target_module TEXT NOT NULL,
target_position INTEGER NOT NULL,
FOREIGN KEY (target_module, target_position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

-- Index for CASCADE deletes: when name_info rows are deleted, find matching internal_names
CREATE INDEX IF NOT EXISTS idx_internal_names_target ON internal_names(target_module, target_position);

CREATE TABLE IF NOT EXISTS constructors (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
type_position INTEGER NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE,
FOREIGN KEY (module_name, type_position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

-- Index for CASCADE deletes on the second FK (type_position)
CREATE INDEX IF NOT EXISTS idx_constructors_type_pos ON constructors(module_name, type_position);

CREATE TABLE IF NOT EXISTS inductives (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
is_unsafe INTEGER NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS class_inductives (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
is_unsafe INTEGER NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS opaques (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
safety TEXT NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS definitions (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
is_unsafe INTEGER NOT NULL,
hints TEXT NOT NULL,
is_noncomputable INTEGER NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS definition_equations (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
code BLOB,
text_length INTEGER NOT NULL,
sequence INTEGER NOT NULL,
PRIMARY KEY (module_name, position, sequence),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS instances (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
class_name TEXT NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS instance_args (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
sequence INTEGER NOT NULL,
type_name TEXT NOT NULL,
PRIMARY KEY (module_name, position, sequence),
FOREIGN KEY (module_name, position) REFERENCES instances(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS structures (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
is_class INTEGER NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS structure_parents (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
sequence INTEGER NOT NULL,
projection_fn TEXT NOT NULL,
type BLOB NOT NULL,
PRIMARY KEY (module_name, position, sequence),
FOREIGN KEY (module_name, position) REFERENCES structures(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS structure_constructors (
module_name TEXT NOT NULL,
position INTEGER NOT NULL, -- The structure's position
ctor_position INTEGER NOT NULL,
name TEXT NOT NULL,
type BLOB NOT NULL,
PRIMARY KEY (module_name, position),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS structure_fields (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
sequence INTEGER NOT NULL,
proj_name TEXT NOT NULL,
type BLOB NOT NULL,
is_direct INTEGER NOT NULL,
PRIMARY KEY (module_name, position, sequence),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
-- Note: No FK on proj_name because the projection function may be in a different module
-- (for inherited fields) that hasn't been processed yet. The JOIN at load time handles this.
);

CREATE TABLE IF NOT EXISTS structure_field_args (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
field_sequence INTEGER NOT NULL,
arg_sequence INTEGER NOT NULL,
binder BLOB NOT NULL,
is_implicit INTEGER NOT NULL,
PRIMARY KEY (module_name, position, field_sequence, arg_sequence),
FOREIGN KEY (module_name, position, field_sequence) REFERENCES structure_fields(module_name, position, sequence) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS declaration_args (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
sequence INTEGER NOT NULL,
binder BLOB NOT NULL,
is_implicit INTEGER NOT NULL,
PRIMARY KEY (module_name, position, sequence),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS declaration_attrs (
module_name TEXT NOT NULL,
position INTEGER NOT NULL,
sequence INTEGER NOT NULL,
attr TEXT NOT NULL,
PRIMARY KEY (module_name, position, sequence),
FOREIGN KEY (module_name, position) REFERENCES name_info(module_name, position) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS tactics (
module_name TEXT NOT NULL,
internal_name TEXT NOT NULL,
user_name TEXT NOT NULL,
doc_string TEXT NOT NULL,
PRIMARY KEY (module_name, internal_name),
FOREIGN KEY (module_name) REFERENCES modules(name) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS tactic_tags (
module_name TEXT NOT NULL,
internal_name TEXT NOT NULL,
tag TEXT NOT NULL,
PRIMARY KEY (module_name, internal_name, tag),
FOREIGN KEY (module_name, internal_name) REFERENCES tactics(module_name, internal_name) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS schema_meta (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
"#

end DocGen4.DB
Loading