diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/sisudoc/outputs/io_out/create_abstraction_db.d | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/sisudoc/outputs/io_out/create_abstraction_db.d b/src/sisudoc/outputs/io_out/create_abstraction_db.d index d953472..a0cbd57 100644 --- a/src/sisudoc/outputs/io_out/create_abstraction_db.d +++ b/src/sisudoc/outputs/io_out/create_abstraction_db.d @@ -178,6 +178,57 @@ template spineAbstractionDb() { CREATE INDEX idx_objects_is_a ON objects(is_a); CREATE INDEX idx_objects_heading ON objects(heading_level) WHERE heading_level IS NOT NULL; + + -- files: what this database carries with it, so that a reader needs + -- nothing beside it. role says what a file is; images are the ones the + -- output writers must have in order to produce a document. bytes are + -- stored exactly as read, so sha256 matches the digest the abstraction + -- was built with + CREATE TABLE files ( + id INTEGER PRIMARY KEY, + role TEXT NOT NULL, + name TEXT NOT NULL, + bytes INTEGER NOT NULL, + sha256 TEXT, + width INTEGER, + height INTEGER, + data BLOB, + UNIQUE(role, name) + ); + + -- the open ended per object lists, one row each, in order + CREATE TABLE object_images ( + object_id INTEGER NOT NULL REFERENCES objects(id), + seq INTEGER NOT NULL, + name TEXT NOT NULL, + bytes INTEGER, + sha256 TEXT, + width INTEGER, + height INTEGER, + missing INTEGER DEFAULT 0, + PRIMARY KEY(object_id, seq) + ); + CREATE TABLE object_links ( + object_id INTEGER NOT NULL REFERENCES objects(id), + seq INTEGER NOT NULL, + url TEXT NOT NULL, + PRIMARY KEY(object_id, seq) + ); + CREATE TABLE object_anchors ( + object_id INTEGER NOT NULL REFERENCES objects(id), + seq INTEGER NOT NULL, + anchor TEXT NOT NULL, + PRIMARY KEY(object_id, seq) + ); + CREATE TABLE object_subtoc ( + object_id INTEGER NOT NULL REFERENCES objects(id), + seq INTEGER NOT NULL, + entry TEXT NOT NULL, + PRIMARY KEY(object_id, seq) + ); + + CREATE INDEX idx_files_role ON files(role); + CREATE INDEX idx_object_images_name ON object_images(name); "); /+ ↓ populate metadata +/ @@ -287,6 +338,25 @@ template spineAbstractionDb() { ~ ")" ); + /+ ↓ the per object lists, one row each +/ + auto img_stmt = db.prepare( + "INSERT INTO object_images" + ~ " (object_id, seq, name, bytes, sha256, width, height, missing)" + ~ " VALUES (:object_id, :seq, :name, :bytes, :sha256, :width, :height, :missing)" + ); + auto lnk_stmt = db.prepare( + "INSERT INTO object_links (object_id, seq, url)" + ~ " VALUES (:object_id, :seq, :url)" + ); + auto anc_stmt = db.prepare( + "INSERT INTO object_anchors (object_id, seq, anchor)" + ~ " VALUES (:object_id, :seq, :anchor)" + ); + auto sub_stmt = db.prepare( + "INSERT INTO object_subtoc (object_id, seq, entry)" + ~ " VALUES (:object_id, :seq, :entry)" + ); + string[] section_order = ["head", "toc", "body", "endnotes", "glossary", "bibliography", "bookindex", "blurb"]; @@ -445,10 +515,126 @@ template spineAbstractionDb() { obj_stmt.execute(); obj_stmt.reset(); + + /+ ↓ the per object lists, keyed on the row just written +/ + long _obj_id = db.lastInsertRowid; + { + int _n = 0; + foreach (i; obj.metainfo.sha256.images) { + img_stmt.bind(":object_id", _obj_id); + img_stmt.bind(":seq", _n); + img_stmt.bind(":name", i.fileName); + img_stmt.bind(":bytes", cast(long) i.fileSize); + img_stmt.bind(":sha256", i.fileHash_sha256.toHexString.to!string); + img_stmt.bind(":width", i.imageWidth); + img_stmt.bind(":height", i.imageHeight); + img_stmt.bind(":missing", i.fileMissing ? 1 : 0); + img_stmt.execute(); + img_stmt.reset(); + ++_n; + } + } + { + int _n = 0; + foreach (lnk; obj.stow.link) { + if (lnk.length == 0) { continue; } + lnk_stmt.bind(":object_id", _obj_id); + lnk_stmt.bind(":seq", _n); + lnk_stmt.bind(":url", lnk); + lnk_stmt.execute(); + lnk_stmt.reset(); + ++_n; + } + } + { + int _n = 0; + foreach (at; obj.tags.anchor_tags) { + if (at.length == 0) { continue; } + anc_stmt.bind(":object_id", _obj_id); + anc_stmt.bind(":seq", _n); + anc_stmt.bind(":anchor", at); + anc_stmt.execute(); + anc_stmt.reset(); + ++_n; + } + } + { + int _n = 0; + foreach (st; obj.tags.lev4_subtoc) { + if (st.length == 0) { continue; } + sub_stmt.bind(":object_id", _obj_id); + sub_stmt.bind(":seq", _n); + sub_stmt.bind(":entry", st); + sub_stmt.execute(); + sub_stmt.reset(); + ++_n; + } + } } } obj_stmt.finalize(); + img_stmt.finalize(); + lnk_stmt.finalize(); + anc_stmt.finalize(); + sub_stmt.finalize(); + + /+ ↓ the document's images, carried inside the file so that output can be + produced from this database alone. bytes exactly as read, and the + digest taken over them, so that it can be checked against the digest + the abstraction recorded +/ + { + import std.digest.sha : sha256Of; + auto file_stmt = db.prepare( + "INSERT OR IGNORE INTO files" + ~ " (role, name, bytes, sha256, width, height, data)" + ~ " VALUES (:role, :name, :bytes, :sha256, :width, :height, :data)" + ); + int[string] _w, _h; + foreach (section; section_order) { + if (section !in doc_abstraction) { continue; } + foreach (obj; doc_abstraction[section]) { + foreach (i; obj.metainfo.sha256.images) { + if (i.imageWidth > 0) { _w[i.fileName] = i.imageWidth; } + if (i.imageHeight > 0) { _h[i.fileName] = i.imageHeight; } + } + } + } + foreach (image; doc_matters.srcs.image_list) { + string _fn = doc_matters.src.image_dir_path ~ "/" ~ image; + ubyte[] _bytes; + try { + if (_fn.exists) { _bytes = cast(ubyte[]) _fn.read; } + } catch (Exception ex) { + _bytes = []; + } + if (_bytes.length == 0) { + if (doc_matters.opt.action.vox_gt_1) { + writeln(" image not carried into abstraction db: ", _fn); + } + continue; + } + file_stmt.bind(":role", "image"); + file_stmt.bind(":name", image); + file_stmt.bind(":bytes", cast(long) _bytes.length); + file_stmt.bind(":sha256", sha256Of(_bytes).toHexString.to!string); + if (image in _w) { file_stmt.bind(":width", _w[image]); } + else { + import std.typecons : Nullable; + file_stmt.bind(":width", Nullable!int()); + } + if (image in _h) { file_stmt.bind(":height", _h[image]); } + else { + import std.typecons : Nullable; + file_stmt.bind(":height", Nullable!int()); + } + file_stmt.bind(":data", _bytes); + file_stmt.execute(); + file_stmt.reset(); + } + file_stmt.finalize(); + } + db.run("COMMIT TRANSACTION"); } } |
