Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Schema::open with simple quickstart_dense test #5

Merged
merged 3 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 7 additions & 5 deletions tiledb/api/src/array/dimension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,21 @@ use crate::Result as TileDBResult;

pub(crate) enum RawDimension {
Owned(*mut ffi::tiledb_dimension_t),
Borrowed(*mut ffi::tiledb_dimension_t),
}

impl Deref for RawDimension {
type Target = *mut ffi::tiledb_dimension_t;
fn deref(&self) -> &Self::Target {
match *self {
RawDimension::Owned(ref ffi) => ffi,
RawDimension::Borrowed(ref ffi) => ffi,
}
}
}

impl Drop for RawDimension {
fn drop(&mut self) {
if let RawDimension::Owned(ref mut ffi) = *self {
unsafe { ffi::tiledb_dimension_free(ffi) }
}
let RawDimension::Owned(ref mut ffi) = *self;
unsafe { ffi::tiledb_dimension_free(ffi) }
}
}

Expand All @@ -39,6 +36,11 @@ impl<'ctx> Dimension<'ctx> {
*self.raw
}

/// Read from the C API whatever we need to use this dimension from Rust
pub(crate) fn new(context: &'ctx Context, raw: RawDimension) -> Self {
Dimension { context, raw }
}

pub fn datatype(&self) -> Datatype {
let c_context = self.context.as_mut_ptr();
let c_dimension = self.capi();
Expand Down
37 changes: 25 additions & 12 deletions tiledb/api/src/array/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,18 @@ impl Drop for RawDomain {
pub struct Domain<'ctx> {
context: &'ctx Context,
raw: RawDomain,
dimensions: Vec<Dimension<'ctx>>,
}

impl<'ctx> Domain<'ctx> {
pub(crate) fn capi(&self) -> *mut ffi::tiledb_domain_t {
*self.raw
}

/// Read from the C API whatever we need to use this domain from Rust
pub(crate) fn new(context: &'ctx Context, raw: RawDomain) -> Self {
Domain { context, raw }
}

pub fn ndim(&self) -> u32 {
let mut ndim: u32 = out_ptr!();
let c_ret = unsafe {
Expand All @@ -49,21 +53,32 @@ impl<'ctx> Domain<'ctx> {
ndim
}

pub fn dimension(&self, idx: u32) -> TileDBResult<Dimension<'ctx>> {
pub fn dimension(&self, idx: usize) -> TileDBResult<Dimension<'ctx>> {
let c_context = self.context.as_mut_ptr();
let c_domain = *self.raw;
let mut c_dimension: *mut ffi::tiledb_dimension_t = out_ptr!();
let c_idx = match idx.try_into() {
Ok(idx) => idx,
Err(e) => {
return Err(crate::error::Error::from(format!(
"Invalid dimension: {}",
e
)))
}
};
let c_ret = unsafe {
ffi::tiledb_domain_get_dimension_from_index(
self.context.as_mut_ptr(),
*self.raw,
idx,
c_context,
c_domain,
c_idx,
&mut c_dimension,
)
};
if c_ret == ffi::TILEDB_OK {
Ok(Dimension {
context: self.context,
raw: RawDimension::Borrowed(c_dimension),
})
Ok(Dimension::new(
self.context,
RawDimension::Owned(c_dimension),
))
} else {
Err(self.context.expect_last_error())
}
Expand All @@ -85,7 +100,6 @@ impl<'ctx> Builder<'ctx> {
domain: Domain {
context,
raw: RawDomain::Owned(c_domain),
dimensions: Vec::new(),
},
})
} else {
Expand All @@ -94,7 +108,7 @@ impl<'ctx> Builder<'ctx> {
}

pub fn add_dimension(
mut self,
self,
dimension: Dimension<'ctx>,
) -> TileDBResult<Self> {
let c_context = self.domain.context.as_mut_ptr();
Expand All @@ -105,7 +119,6 @@ impl<'ctx> Builder<'ctx> {
ffi::tiledb_domain_add_dimension(c_context, c_domain, c_dim)
};
if c_ret == ffi::TILEDB_OK {
self.domain.dimensions.push(dimension);
Ok(self)
} else {
Err(self.domain.context.expect_last_error())
Expand Down
42 changes: 27 additions & 15 deletions tiledb/api/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,25 +148,23 @@ impl Drop for Array<'_> {
}

#[cfg(test)]
mod tests {
pub mod tests {
use std::io;
use tempdir::TempDir;

use crate::array::*;
use crate::context::Context;
use crate::Datatype;

#[test]
fn test_array_create() -> io::Result<()> {
let tmp_dir = TempDir::new("test_rs_bdelit")?;
let arr_dir = tmp_dir.path().join("create_test");

let c: Context = Context::new().unwrap();

// "quickstart_dense" example
/// Create the array used in the "quickstart_dense" example
pub fn create_quickstart_dense(
dir: &TempDir,
context: &Context,
) -> TileDBResult<String> {
let arr_dir = dir.path().join("quickstart_dense");
let d: Domain = {
let rows: Dimension = DimensionBuilder::new::<i32>(
&c,
context,
"rows",
Datatype::Int32,
&[1, 4],
Expand All @@ -175,7 +173,7 @@ mod tests {
.expect("Error constructing rows dimension")
.build();
let cols: Dimension = DimensionBuilder::new::<i32>(
&c,
context,
"cols",
Datatype::Int32,
&[1, 4],
Expand All @@ -184,7 +182,7 @@ mod tests {
.expect("Error constructing cols dimension")
.build();

DomainBuilder::new(&c)
DomainBuilder::new(context)
.unwrap()
.add_dimension(rows)
.unwrap()
Expand All @@ -193,15 +191,29 @@ mod tests {
.build()
};

let s: Schema = SchemaBuilder::new(&c, ArrayType::Sparse, d)
let s: Schema = SchemaBuilder::new(context, ArrayType::Sparse, d)
.unwrap()
.add_attribute(Attribute::new(&c, "a", Datatype::UInt64).unwrap())
.add_attribute(
Attribute::new(context, "a", Datatype::UInt64).unwrap(),
)
.unwrap()
.into();

// domain not set
// TODO
assert!(Array::create(&c, arr_dir.to_str().unwrap(), s).is_ok());
Array::create(context, arr_dir.to_str().unwrap(), s)?;

Ok(String::from(arr_dir.to_str().unwrap()))
}

#[test]
fn test_array_create() -> io::Result<()> {
let tmp_dir = TempDir::new("test_rs_bdelit")?;

let c: Context = Context::new().unwrap();

let r = create_quickstart_dense(&tmp_dir, &c);
assert!(r.is_ok());

// Make sure we can remove the array we created.
tmp_dir.close()?;
Expand Down
105 changes: 92 additions & 13 deletions tiledb/api/src/array/schema.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::ops::Deref;

use crate::array::domain::RawDomain;
use crate::array::{Attribute, Domain};
use crate::context::Context;
use crate::Result as TileDBResult;
Expand All @@ -20,41 +21,80 @@ impl ArrayType {

/// Wrapper for the CAPI handle.
/// Ensures that the CAPI structure is freed.
pub(crate) struct RawSchema {
ffi: *mut ffi::tiledb_array_schema_t,
}

impl RawSchema {
pub fn new(ffi: *mut ffi::tiledb_array_schema_t) -> Self {
RawSchema { ffi }
}
pub(crate) enum RawSchema {
Owned(*mut ffi::tiledb_array_schema_t),
}

impl Deref for RawSchema {
type Target = *mut ffi::tiledb_array_schema_t;

fn deref(&self) -> &Self::Target {
&self.ffi
let RawSchema::Owned(ref ffi) = *self;
ffi
}
}

impl Drop for RawSchema {
fn drop(&mut self) {
unsafe { ffi::tiledb_array_schema_free(&mut self.ffi) }
unsafe {
let RawSchema::Owned(ref mut ffi) = *self;
ffi::tiledb_array_schema_free(ffi)
}
}
}

pub struct Schema<'ctx> {
context: &'ctx Context,
raw: RawSchema,
_domain: Domain<'ctx>,
}

impl<'ctx> Schema<'ctx> {
pub(crate) fn new(context: &'ctx Context, raw: RawSchema) -> Self {
Schema { context, raw }
}

pub(crate) fn as_mut_ptr(&self) -> *mut ffi::tiledb_array_schema_t {
*self.raw
}

pub fn domain(&self) -> TileDBResult<Domain<'ctx>> {
let c_context: *mut ffi::tiledb_ctx_t = self.context.as_mut_ptr();
let c_schema = *self.raw;
let mut c_domain: *mut ffi::tiledb_domain_t = out_ptr!();
let c_ret = unsafe {
ffi::tiledb_array_schema_get_domain(
c_context,
c_schema,
&mut c_domain,
)
};
if c_ret == ffi::TILEDB_OK {
Ok(Domain::new(self.context, RawDomain::Owned(c_domain)))
} else {
Err(self.context.expect_last_error())
}
}

/// Retrieve the schema of an array from storage
pub fn load(context: &'ctx Context, uri: &str) -> TileDBResult<Self> {
let c_context: *mut ffi::tiledb_ctx_t = context.as_mut_ptr();
let c_uri = cstring!(uri);
let mut c_schema: *mut ffi::tiledb_array_schema_t = out_ptr!();

let c_ret = unsafe {
ffi::tiledb_array_schema_load(
c_context,
c_uri.as_ptr(),
&mut c_schema,
)
};
if c_ret == ffi::TILEDB_OK {
Ok(Schema::new(context, RawSchema::Owned(c_schema)))
} else {
Err(context.expect_last_error())
}
}

pub fn version(&self) -> i64 {
let mut c_ret: std::os::raw::c_int = out_ptr!();
if unsafe {
Expand Down Expand Up @@ -124,8 +164,7 @@ impl<'ctx> Builder<'ctx> {
Ok(Builder {
schema: Schema {
context,
raw: RawSchema::new(c_schema),
_domain: domain,
raw: RawSchema::Owned(c_schema),
},
})
}
Expand Down Expand Up @@ -174,7 +213,11 @@ impl<'ctx> From<Builder<'ctx>> for Schema<'ctx> {

#[cfg(test)]
mod tests {
use std::io;
use tempdir::TempDir;

use crate::array::schema::*;
use crate::array::tests::*;
use crate::array::{DimensionBuilder, DomainBuilder};
use crate::context::Context;
use crate::Datatype;
Expand Down Expand Up @@ -255,4 +298,40 @@ mod tests {
assert!(s.allows_duplicates());
}
}

#[test]
fn test_load() -> io::Result<()> {
let tmp_dir = TempDir::new("tiledb_array_schema_test_load")?;

let c: Context = Context::new().unwrap();

let r = create_quickstart_dense(&tmp_dir, &c);
assert!(r.is_ok());

let schema = Schema::load(&c, &r.unwrap())
.expect("Could not open quickstart_dense schema");

let domain = schema.domain().expect("Error reading domain");

let rows = domain.dimension(0).expect("Error reading rows dimension");
assert_eq!(Datatype::Int32, rows.datatype());
// TODO: add method to check min/max

let cols = domain.dimension(1).expect("Error reading cols dimension");
assert_eq!(Datatype::Int32, rows.datatype());
// TODO: add method to check min/max

let rows_domain = rows.domain::<i32>().unwrap();
assert_eq!(rows_domain[0], 1);
assert_eq!(rows_domain[1], 4);

let cols_domain = cols.domain::<i32>().unwrap();
assert_eq!(cols_domain[0], 1);
assert_eq!(cols_domain[1], 4);

// Make sure we can remove the array we created.
tmp_dir.close()?;

Ok(())
}
}