#![allow(dead_code)]
pub mod gpkg_wkb;
mod sql;
pub mod srs;
pub mod types;
use crate::sql::table_definitions::*;
use crate::srs::{defaults::*, SpatialRefSys};
use geo_types::Polygon;
pub use gpkg_derive::GPKGModel;
use rusqlite::{params, Connection, DatabaseName, OpenFlags, Result};
use std::path::Path;
pub struct GeoPackage {
pub conn: Connection,
tables: Vec<TableDefinition>,
}
pub trait GPKGModel<'a>: Sized {
fn create_table(gpkg: &GeoPackage) -> Result<()>;
fn insert_record(&self, gpkg: &GeoPackage) -> Result<()>;
fn get_first(gpkg: &GeoPackage) -> Result<Option<Self>>;
fn get_all(gpkg: &GeoPackage) -> Result<Vec<Self>>;
fn get_where(gpkg: &GeoPackage, predicate: &str) -> Result<Vec<Self>>;
}
struct ATestTable<'a> {
start_node: i64,
end_node: i64,
for_cost: f64,
rev_cost: &'a [u8],
geom: Polygon<f64>,
}
struct TableDefinition {
name: String,
}
impl GeoPackage {
pub fn create<P: AsRef<Path>>(path: P) -> Result<GeoPackage> {
let conn = Connection::open(path)?;
let gpkg = GeoPackage {
conn,
tables: Vec::new(),
};
gpkg.conn
.pragma_update(Some(DatabaseName::Main), "application_id", 0x47504B47)?;
gpkg.conn
.pragma_update(Some(DatabaseName::Main), "user_version", 10300)?;
gpkg.conn.execute(CREATE_SPATIAL_REF_SYS_TABLE, [])?;
gpkg.new_srs(&WGS84)?;
gpkg.new_srs(&CARTESIAN)?;
gpkg.new_srs(&GEOGRAPHIC)?;
gpkg.conn.execute(CREATE_CONTENTS_TABLE, [])?;
gpkg.conn.execute(CREATE_GEOMETRY_COLUMNS_TABLE, [])?;
gpkg.conn.execute(CREATE_EXTENSTIONS_TABLE, [])?;
gpkg.conn.execute(CREATE_TILE_MATRIX_TABLE, [])?;
gpkg.conn.execute(CREATE_TILE_MATRIX_SET_TABLE, [])?;
Ok(gpkg)
}
pub fn new_srs(&self, srs: &SpatialRefSys) -> Result<()> {
const STMT: &str = "INSERT INTO gpkg_spatial_ref_sys VALUES (?1, ?2, ?3, ?4, ?5, ?6)";
self.conn.execute(
STMT,
params![
srs.name,
srs.id,
srs.organization,
srs.organization_coordsys_id,
srs.definition,
srs.description,
],
)?;
Ok(())
}
pub fn close(self) {
self.conn.close().unwrap();
}
pub fn open<P: AsRef<Path>>(path: P) -> Result<GeoPackage> {
let conn = Connection::open_with_flags(path, OpenFlags::SQLITE_OPEN_READ_WRITE)?;
let application_id: u32 =
conn.query_row("SELECT * FROM pragma_application_id()", [], |row| {
row.get(0)
})?;
assert_eq!(application_id, 0x47504B47);
let user_version: u32 =
conn.query_row("SELECT * FROM pragma_user_version()", [], |row| row.get(0))?;
dbg!(user_version);
let integrity_check: String =
conn.query_row("SELECT * FROM pragma_integrity_check()", [], |row| {
row.get(0)
})?;
assert_eq!(integrity_check, "ok".to_owned());
{
let mut stmt = conn.prepare("SELECT * FROM pragma_foreign_key_check()")?;
let mut rows = stmt.query([])?;
assert!(rows.next()?.is_none());
}
let tables = Vec::new();
Ok(GeoPackage { conn, tables })
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
use geo_types::{coord, LineString, Point, Polygon};
use crate::types::*;
use super::*;
#[derive(GPKGModel, Debug)]
#[table_name = "test"]
struct TestTable {
start_node: Option<i64>,
end_node: i64,
rev_cost: String,
#[geom_field]
geom: types::GPKGLineStringZ,
}
#[test]
fn new_gpkg() {
let path = Path::new("../test_data/create.gpkg");
let db = GeoPackage::create(path).unwrap();
TestTable::create_table(&db).expect("Problem creating table");
let val = TestTable {
start_node: Some(42),
end_node: 918,
rev_cost: "Test values".to_owned(),
geom: GPKGLineStringZ(vec![
GPKGPointZ {
x: 40.0,
y: -105.0,
z: 5280.0,
},
GPKGPointZ {
x: 41.0,
y: -106.0,
z: 5280.0,
},
]),
};
let val2 = TestTable {
start_node: Some(45),
end_node: 918,
rev_cost: "Test values".to_owned(),
geom: GPKGLineStringZ(vec![
GPKGPointZ {
x: 40.0,
y: -105.0,
z: 5280.0,
},
GPKGPointZ {
x: 41.0,
y: -106.0,
z: 5280.0,
},
]),
};
let val3 = TestTable {
start_node: Some(48),
end_node: 918,
rev_cost: "Test values".to_owned(),
geom: GPKGLineStringZ(vec![
GPKGPointZ {
x: 40.0,
y: -105.0,
z: 5280.0,
},
GPKGPointZ {
x: 41.0,
y: -106.0,
z: 5280.0,
},
]),
};
val.insert_record(&db).unwrap();
val2.insert_record(&db).unwrap();
val3.insert_record(&db).unwrap();
println!("{:?}", TestTable::get_where(&db, "start_node > 50"));
db.close();
GeoPackage::open(path).unwrap();
let result = 2 + 2;
assert_eq!(result, 4);
}
}