Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions crates/lance-context-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,36 @@ pub trait ContextStoreApi {

fn get(&self, id: &str) -> impl Future<Output = ContextResult<Option<RecordDto>>> + Send;

fn get_by_external_id(
&self,
external_id: &str,
) -> impl Future<Output = ContextResult<Option<RecordDto>>> + Send;

fn delete_by_id(
&mut self,
id: &str,
) -> impl Future<Output = ContextResult<DeleteRecordResponse>> + Send;

fn delete_by_external_id(
&mut self,
external_id: &str,
) -> impl Future<Output = ContextResult<DeleteRecordResponse>> + Send;

fn list(
&self,
limit: Option<usize>,
offset: Option<usize>,
) -> impl Future<Output = ContextResult<Vec<RecordDto>>> + Send;

fn related(
&self,
target_id: &str,
relation: Option<&str>,
limit: Option<usize>,
include_expired: bool,
include_retired: bool,
) -> impl Future<Output = ContextResult<Vec<RecordDto>>> + Send;

fn search(
&self,
query: &[f32],
Expand Down Expand Up @@ -225,6 +249,12 @@ pub struct GetRecordResponse {
pub record: Option<RecordDto>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DeleteRecordResponse {
pub deleted: bool,
pub version: u64,
}

// ---------------------------------------------------------------------------
// Search
// ---------------------------------------------------------------------------
Expand Down
126 changes: 126 additions & 0 deletions crates/lance-context-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,38 @@ impl ContextStoreApi for RemoteContextStore {
Ok(resp.record)
}

async fn get_by_external_id(&self, external_id: &str) -> ContextResult<Option<RecordDto>> {
let resp = self
.client
.get_record_by_external_id(&self.context_name, external_id)
.await
.map_err(to_ctx_err)?;
Ok(resp.record)
}

async fn delete_by_id(&mut self, id: &str) -> ContextResult<DeleteRecordResponse> {
let resp = self
.client
.delete_record(&self.context_name, id)
.await
.map_err(to_ctx_err)?;
self.cached_version = resp.version;
Ok(resp)
}

async fn delete_by_external_id(
&mut self,
external_id: &str,
) -> ContextResult<DeleteRecordResponse> {
let resp = self
.client
.delete_record_by_external_id(&self.context_name, external_id)
.await
.map_err(to_ctx_err)?;
self.cached_version = resp.version;
Ok(resp)
}

async fn list(
&self,
limit: Option<usize>,
Expand All @@ -80,6 +112,29 @@ impl ContextStoreApi for RemoteContextStore {
Ok(resp.records)
}

async fn related(
&self,
target_id: &str,
relation: Option<&str>,
limit: Option<usize>,
include_expired: bool,
include_retired: bool,
) -> ContextResult<Vec<RecordDto>> {
let resp = self
.client
.related_records(
&self.context_name,
target_id,
relation,
limit,
include_expired,
include_retired,
)
.await
.map_err(to_ctx_err)?;
Ok(resp.records)
}

async fn search(
&self,
query: &[f32],
Expand Down Expand Up @@ -246,6 +301,47 @@ impl ContextClient {
Self::handle_response(resp).await
}

pub async fn get_record_by_external_id(
&self,
name: &str,
external_id: &str,
) -> Result<GetRecordResponse, ClientError> {
let resp = self
.http
.get(self.url(&format!("/contexts/{}/records/by-external-id", name)))
.query(&[("external_id", external_id)])
.send()
.await?;
Self::handle_response(resp).await
}

pub async fn delete_record(
&self,
name: &str,
id: &str,
) -> Result<DeleteRecordResponse, ClientError> {
let resp = self
.http
.delete(self.url(&format!("/contexts/{}/records/{}", name, id)))
.send()
.await?;
Self::handle_response(resp).await
}

pub async fn delete_record_by_external_id(
&self,
name: &str,
external_id: &str,
) -> Result<DeleteRecordResponse, ClientError> {
let resp = self
.http
.delete(self.url(&format!("/contexts/{}/records", name)))
.query(&[("external_id", external_id)])
.send()
.await?;
Self::handle_response(resp).await
}

pub async fn list_records(
&self,
name: &str,
Expand All @@ -268,6 +364,36 @@ impl ContextClient {
Self::handle_response(resp).await
}

pub async fn related_records(
&self,
name: &str,
target_id: &str,
relation: Option<&str>,
limit: Option<usize>,
include_expired: bool,
include_retired: bool,
) -> Result<ListRecordsResponse, ClientError> {
let mut request = self
.http
.get(self.url(&format!("/contexts/{}/records/related", name)))
.query(&[("target_id", target_id)]);
if let Some(relation) = relation {
request = request.query(&[("relation", relation)]);
}
if let Some(limit) = limit {
request = request.query(&[("limit", limit)]);
}
if include_expired {
request = request.query(&[("include_expired", include_expired)]);
}
if include_retired {
request = request.query(&[("include_retired", include_retired)]);
}

let resp = request.send().await?;
Self::handle_response(resp).await
}

pub async fn search(
&self,
name: &str,
Expand Down
50 changes: 48 additions & 2 deletions crates/lance-context-core/src/api_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use uuid::Uuid;

use lance_context_api::{
AddRecordRequest, AddRecordsResponse, CompactRequest, CompactResponse, CompactStatsResponse,
ContextError, ContextResult, ContextStoreApi, RecordDto, RelationshipDto, RetrieveRequest,
RetrieveResultDto, SearchResultDto, StateMetadataDto,
ContextError, ContextResult, ContextStoreApi, DeleteRecordResponse, RecordDto, RelationshipDto,
RetrieveRequest, RetrieveResultDto, SearchResultDto, StateMetadataDto,
};

use crate::record::{
Expand Down Expand Up @@ -71,6 +71,36 @@ impl ContextStoreApi for ContextStore {
Ok(record.map(record_to_dto))
}

async fn get_by_external_id(&self, external_id: &str) -> ContextResult<Option<RecordDto>> {
let record = ContextStore::get_by_external_id(self, external_id)
.await
.map_err(to_ctx_err)?;
Ok(record.map(record_to_dto))
}

async fn delete_by_id(&mut self, id: &str) -> ContextResult<DeleteRecordResponse> {
let deleted = ContextStore::delete_by_id(self, id)
.await
.map_err(to_ctx_err)?;
Ok(DeleteRecordResponse {
deleted,
version: ContextStore::version(self),
})
}

async fn delete_by_external_id(
&mut self,
external_id: &str,
) -> ContextResult<DeleteRecordResponse> {
let deleted = ContextStore::delete_by_external_id(self, external_id)
.await
.map_err(to_ctx_err)?;
Ok(DeleteRecordResponse {
deleted,
version: ContextStore::version(self),
})
}

async fn list(
&self,
limit: Option<usize>,
Expand All @@ -82,6 +112,22 @@ impl ContextStoreApi for ContextStore {
Ok(records.into_iter().map(record_to_dto).collect())
}

async fn related(
&self,
target_id: &str,
relation: Option<&str>,
limit: Option<usize>,
include_expired: bool,
include_retired: bool,
) -> ContextResult<Vec<RecordDto>> {
let options = LifecycleQueryOptions::new(include_expired, include_retired);
let records =
ContextStore::list_related_with_options(self, target_id, relation, limit, options)
.await
.map_err(to_ctx_err)?;
Ok(records.into_iter().map(record_to_dto).collect())
}

async fn search(
&self,
query: &[f32],
Expand Down
3 changes: 3 additions & 0 deletions crates/lance-context-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ tower-http = { version = "0.6", features = ["cors", "trace"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
uuid = { version = "1", features = ["v4"] }

[dev-dependencies]
tempfile = "3"
26 changes: 26 additions & 0 deletions crates/lance-context-server/src/routes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,26 @@ pub fn router() -> Router<Arc<AppState>> {
"/api/v1/contexts/{name}/records",
get(records::list_records),
)
.route(
"/api/v1/contexts/{name}/records",
delete(records::delete_record_by_external_id),
)
.route(
"/api/v1/contexts/{name}/records/by-external-id",
get(records::get_record_by_external_id),
)
.route(
"/api/v1/contexts/{name}/records/related",
get(records::related_records),
)
.route(
"/api/v1/contexts/{name}/records/{id}",
get(records::get_record),
)
.route(
"/api/v1/contexts/{name}/records/{id}",
delete(records::delete_record),
)
.route("/api/v1/contexts/{name}/search", post(search::search))
.route("/api/v1/contexts/{name}/retrieve", post(search::retrieve))
.route(
Expand All @@ -44,3 +60,13 @@ pub fn router() -> Router<Arc<AppState>> {
get(compact::compact_stats),
)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn router_builds_with_record_parity_routes() {
let _ = router();
}
}
Loading
Loading