| Crates.io | cellulite |
| lib.rs | cellulite |
| version | 0.3.0 |
| created_at | 2025-07-23 16:10:18.078515+00 |
| updated_at | 2025-09-23 09:17:49.323996+00 |
| description | Store and retrieve geojson in a memory mapped database |
| homepage | |
| repository | https://github.com/irevoire/cellulite |
| max_upload_size | |
| id | 1764985 |
| size | 224,118 |
Cellulite is a crate based on LMDB for storing and retrieving shapes in the geojson format.
The entry point of the crate is the [Cellulite] structure which contains all the LMDB database required.
The preferred way of initializing it is through the [Cellulite::create_from_env] static method.
use cellulite::Cellulite;
let env = unsafe {
heed::EnvOpenOptions::new()
.map_size(200 * 1024 * 1024 * 1024)
.max_dbs(Cellulite::nb_dbs())
.open("path/to/your/database")
}
.unwrap();
let mut wtxn = env.write_txn().unwrap();
let cellulite = Cellulite::create_from_env(&env, &mut wtxn, "cellulite").unwrap();
Once the databases are initialized, the only two actions possible with the database are
# let (cellulite, env): (cellulite::Cellulite, heed::Env) = todo!();
use geojson::GeoJson;
// We'll need a write transaction in order to write in the database
let mut wtxn = env.write_txn().unwrap();
// First let's add a document:
let geojson_str = r#"
{
"type": "Feature",
"properties": { "food": "donuts" },
"geometry": {
"type": "Point",
"coordinates": [ -118.2836, 34.0956 ]
}
}
"#;
let geojson: GeoJson = geojson_str.parse::<GeoJson>().unwrap();
// The parameters are:
// 1. The write transaction: to be able to write in the databases
// 2. The ID of the document is a `u32`. If a document already exists with the
// same ID, it'll be removed and replaced by the new one
// 3. The geojson we want to insert
cellulite.add(&mut wtxn, 0, &geojson).unwrap();
// The parameters are:
// 1. The write transaction: to be able to write in the databases
// 2. The ID of the document to remove
cellulite.delete(&mut wtxn, 35).unwrap();
// Finally, we must build our database with all the changes we applied.
// The parameters are:
// 1. The write transaction: to be able to write in the databases
// 2. A closure that can return `true` if we need to cancel the build asap
// 3. Anything that implements the [`steppe::Progress`] trait to follow the progress of the build
cellulite.build(&mut wtxn, &|| false, &steppe::NoProgress);
When we insert documents into the databases, they're not saved as-is and thus cannot be returned. This means, if you need to get back the original geojson it's your job to save it somewhere, the methods we're going to see in this part are only returning the IDs of the matching documents:
# let (cellulite, env): (cellulite::Cellulite, heed::Env) = todo!();
use geo::{polygon, point};
// We only need a read transaction to search in the database
let mut rtxn = env.read_txn().unwrap();
// The main way of searching for documents is through the `in_shape` method:
// - The first parameter is the read transaction required to read from the database
// - The second parameter is the polygon you want to retrieve the documents in
// Note: Cellulite returns both the shapes contained inside the polygon or intersecting with the polygon.
let _doc_ids = cellulite.in_shape(&rtxn, &polygon![
(x: -111., y: 45.),
(x: -111., y: 41.),
(x: -104., y: 41.),
(x: -104., y: 45.),
]).unwrap();
// The other method available for search is [`Cellulite::in_circle`], which doesn't search in a perfect
// circle though, it searches in a polygon, doing an approximation of a circle.
// - The first parameter is the read transaction required to read from the database
// - The second parameter is the center of the circle you want to search in
// - The third parameter is its radius
// - The fourth parameter is the resolution of the polygon to circle approximation. It represents the
// number of points that should compose the polygon. More points mean a more precise and slower search.
let _doc_ids = cellulite.in_circle(&rtxn, point! { x: 181.2, y: 51.79 }, 1000.0, 15).unwrap();