geolite

database

store admin data in ~/.geolite/database.sqlite3 (layers 1, 4, 5); raw OSM primitives (layers 2–3) live in a sibling ~/.geolite/database.osm_data.sqlite3, attached at runtime as schema osm_data

layers

layer 5  ·  admin_levels_hierarchy     one edge child > parent per row; parent_id for the downward read — admin_level_hierarchy
         ·  admin_levels_rtree         virtual rtree: bbox spatial index for fast coord lookup — admin_level
            ─────────────────────────────────────────────────────────────────────────────────
layer 4  ·  admin_levels               admin areas — levels 1–9 (admin_level tag), 10 (place ways), 12 (streets) — admin_level
         ·  house_numbers              address nodes linked to a street (admin_levels row) — house_number
            ─────────────────────────────────────────────────────────────────────────────────
layer 3  ·  osm_nodes / osm_ways / osm_relations    raw OSM primitives — osm_node, osm_way, osm_relation
            ─────────────────────────────────────────────────────────────────────────────────
layer 2  ·  osm_pbf_blob_chunks        byte ranges of each blob (header=0 / data=1)
            ─────────────────────────────────────────────────────────────────────────────────
layer 1  ·  osm_pbf_files              one row per .osm.pbf — origin (local_path, geofabrik, url) and its coverage, download state, header and counts

admin_levels and its rtree are owned by admin_level, admin_levels_hierarchy by admin_level_hierarchy house_numbers by house_number and the three element tables by osm_node, osm_way and osm_relation; this folder keeps the connection lifecycle that creates them, the table trait every repository implements, the shared helpers behind their sql (placeholders_for, query_by_ids, insert_in_chunks) and the generic jsonb codec.

layers are built roughly bottom-up (back-references: house_numbers → admin_levels, and the *_count columns on osm_pbf_files). destroy_data selectively drops upper layers — deleting the osm_data sibling file when layer 2 goes, and dropping only the three element tables when layer 3 goes alone, so the chunk index survives a --recreate of the osm-data stage — then vacuums; osm_pbf_files is kept.

compact is the end of a build: ANALYZE, PRAGMA optimize, wal_checkpoint(TRUNCATE) and VACUUM on the main file, answering with the bytes before and after; remove_osm_data_files deletes the osm_data sibling with its -wal and -shm and answers with the bytes freed. destroy_data uses the second, geolite exec optimize-sqlite-file and geolite merge the first.

every writable connection runs in WAL mode; the schema is stamped via PRAGMA user_version (SCHEMA_VERSION): a writable open refuses a database stamped with another version, and geolite merge refuses to combine builds with an incompatible one. a column that only extends the schema is added to an older database on open (ALTER TABLE), without a new version: osm_pbf_files.origin_wkt and admin_levels.merged_way_ids came that way, each guarded by has_column, which takes the schema so it can also ask an attached database.

merge_source copies merged_way_ids with the wkb it describes, in the one upsert. a source is attached read-only and cannot gain the column, so one built before it answers NULL there, and the street merge that follows traces what it folds.

jsonb.rs is the generic codec behind every payload column: sqlite’s jsonb binary format — headers, size classes, objects and arrays — with no knowledge of what is written; each element folder’s payload module writes its own shape with it, once per element in the extraction’s decoder threads, and every reader gets it back with JSON(payload). admin_levels.merged_way_ids is the one json column that does not go through it: a short array written a few thousand times by the street merge, bound as json text under JSONB(?n).