From a19767b1908b53f110bbf251f9feec136589a687 Mon Sep 17 00:00:00 2001 From: Ben Artuso Date: Tue, 23 Jan 2024 11:59:18 -0500 Subject: [PATCH] adding get schema by hash route + optional schema node on list versions --- src/lib/src/api/local/schemas.rs | 13 ++++++++++++- src/lib/src/view/entry.rs | 1 + src/lib/src/view/schema.rs | 7 +++++++ src/server/src/controllers/branches.rs | 20 ++++++++++++++++++-- src/server/src/controllers/schemas.rs | 24 +++++++++++++++++++++++- src/server/src/routes.rs | 4 ++++ 6 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/lib/src/api/local/schemas.rs b/src/lib/src/api/local/schemas.rs index 9ea002f91..ebbb63f34 100644 --- a/src/lib/src/api/local/schemas.rs +++ b/src/lib/src/api/local/schemas.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use crate::api; +use crate::{api, util}; use crate::core::index::SchemaReader; use crate::error::OxenError; @@ -69,3 +69,14 @@ pub fn get_by_path_from_ref( Err(OxenError::revision_not_found(revision.into())) } } + +pub fn get_by_hash(repo: &LocalRepository, hash: String) -> Result, OxenError> { + let version_path = util::fs::version_path_from_schema_hash(repo.path.clone(), hash); + // Read schema from that path + if version_path.exists() { + let schema: Schema = serde_json::from_reader(std::fs::File::open(version_path)?)?; + Ok(Some(schema)) + } else { + Ok(None) + } +} diff --git a/src/lib/src/view/entry.rs b/src/lib/src/view/entry.rs index e6d291776..c80dd7c16 100644 --- a/src/lib/src/view/entry.rs +++ b/src/lib/src/view/entry.rs @@ -100,6 +100,7 @@ pub struct BranchEntryVersion { pub struct CommitEntryVersion { pub commit: crate::model::Commit, pub resource: ResourceVersion, + pub schema_hash: Option, } #[derive(Deserialize, Serialize, Debug)] diff --git a/src/lib/src/view/schema.rs b/src/lib/src/view/schema.rs index 7d0514865..e4eea29c4 100644 --- a/src/lib/src/view/schema.rs +++ b/src/lib/src/view/schema.rs @@ -26,3 +26,10 @@ pub struct ListSchemaResponse { pub commit: Option, pub resource: Option, } + +/* For getting schemas directly by hash - no path associated */ +#[derive(Serialize, Deserialize, Debug)] +pub struct SchemaResponse { + pub status: StatusMessage, + pub schema: Schema, +} diff --git a/src/server/src/controllers/branches.rs b/src/server/src/controllers/branches.rs index 19af0cc59..59e009df1 100644 --- a/src/server/src/controllers/branches.rs +++ b/src/server/src/controllers/branches.rs @@ -6,9 +6,9 @@ use crate::params::{app_data, path_param, PageNumQuery}; use actix_web::{web, HttpRequest, HttpResponse}; -use liboxen::core::index::Merger; +use liboxen::core::index::{Merger, SchemaReader}; use liboxen::error::OxenError; -use liboxen::util::paginate; +use liboxen::util::{self, paginate}; use liboxen::view::entry::ResourceVersion; use liboxen::view::{ BranchLockResponse, BranchNewFromExisting, BranchRemoteMerge, BranchResponse, BranchUpdate, @@ -269,12 +269,28 @@ pub async fn list_entry_versions( let mut commit_versions: Vec = Vec::new(); for (commit, entry) in commits_with_versions { + // For each version, get the schema hash if one exists. + let maybe_schema_hash = if util::fs::is_tabular(&entry.path) { + let schema_reader = SchemaReader::new(&repo, &commit.id)?; + let maybe_schema = schema_reader.get_schema_for_file(&entry.path)?; + match maybe_schema { + Some(schema) => Some(schema.hash), + None => { + log::error!("Could not get schema for tabular file {:?}", entry.path); + None + } + } + } else { + None + }; + commit_versions.push(CommitEntryVersion { commit: commit.clone(), resource: ResourceVersion { version: commit.id.clone(), path: entry.path.to_string_lossy().into(), }, + schema_hash: maybe_schema_hash, }); } diff --git a/src/server/src/controllers/schemas.rs b/src/server/src/controllers/schemas.rs index 419b3cb2e..d3e17eeb3 100644 --- a/src/server/src/controllers/schemas.rs +++ b/src/server/src/controllers/schemas.rs @@ -7,7 +7,7 @@ use crate::params::{app_data, parse_resource, path_param}; use liboxen::core::df::tabular; use liboxen::model::Schema; use liboxen::opts::DFOpts; -use liboxen::view::schema::SchemaWithPath; +use liboxen::view::schema::{SchemaResponse, SchemaWithPath}; use liboxen::{api, util}; use actix_web::{HttpRequest, HttpResponse}; @@ -112,3 +112,25 @@ pub async fn list_or_get(req: HttpRequest) -> actix_web::Result actix_web::Result { + let app_data = app_data(&req)?; + + let namespace = path_param(&req, "namespace")?; + let repo_name = path_param(&req, "repo_name")?; + let repo = get_repo(&app_data.path, namespace, repo_name)?; + + let hash = path_param(&req, "hash")?; + + let maybe_schema = api::local::schemas::get_by_hash(&repo, hash)?; + + if let Some(schema) = maybe_schema { + let response = SchemaResponse { + status: StatusMessage::resource_found(), + schema, + }; + Ok(HttpResponse::Ok().json(response)) + } else { + Err(OxenHttpError::NotFound) + } +} diff --git a/src/server/src/routes.rs b/src/server/src/routes.rs index 9dbfcdbd9..9aee4463e 100644 --- a/src/server/src/routes.rs +++ b/src/server/src/routes.rs @@ -280,6 +280,10 @@ pub fn config(cfg: &mut web::ServiceConfig) { web::get().to(controllers::entries::download_data_from_version_paths), ) // ----- Schemas ----- // + .route( + "/{namespace}/{repo_name}/schemas/hash/{hash}", + web::get().to(controllers::schemas::get_by_hash), + ) .route( "/{namespace}/{repo_name}/schemas/{resource:.*}", web::get().to(controllers::schemas::list_or_get),