node running, runtime version awareness

This commit is contained in:
2026-02-25 23:24:07 -06:00
parent e89b5991ec
commit 495b81236a
54 changed files with 4308 additions and 246 deletions

View File

@@ -0,0 +1,447 @@
//! Repository for runtime version operations
//!
//! Provides CRUD operations and specialized queries for the `runtime_version`
//! table, which stores version-specific execution configurations for runtimes.
use crate::error::Result;
use crate::models::{Id, RuntimeVersion};
use crate::repositories::{Create, Delete, FindById, List, Repository, Update};
use sqlx::{Executor, Postgres, QueryBuilder};
/// Repository for runtime version database operations
pub struct RuntimeVersionRepository;
impl Repository for RuntimeVersionRepository {
type Entity = RuntimeVersion;
fn table_name() -> &'static str {
"runtime_version"
}
}
/// Input for creating a new runtime version
#[derive(Debug, Clone)]
pub struct CreateRuntimeVersionInput {
pub runtime: Id,
pub runtime_ref: String,
pub version: String,
pub version_major: Option<i32>,
pub version_minor: Option<i32>,
pub version_patch: Option<i32>,
pub execution_config: serde_json::Value,
pub distributions: serde_json::Value,
pub is_default: bool,
pub available: bool,
pub meta: serde_json::Value,
}
/// Input for updating an existing runtime version
#[derive(Debug, Clone, Default)]
pub struct UpdateRuntimeVersionInput {
pub version: Option<String>,
pub version_major: Option<Option<i32>>,
pub version_minor: Option<Option<i32>>,
pub version_patch: Option<Option<i32>>,
pub execution_config: Option<serde_json::Value>,
pub distributions: Option<serde_json::Value>,
pub is_default: Option<bool>,
pub available: Option<bool>,
pub verified_at: Option<Option<chrono::DateTime<chrono::Utc>>>,
pub meta: Option<serde_json::Value>,
}
const SELECT_COLUMNS: &str = r#"
id, runtime, runtime_ref, version,
version_major, version_minor, version_patch,
execution_config, distributions,
is_default, available, verified_at, meta,
created, updated
"#;
#[async_trait::async_trait]
impl FindById for RuntimeVersionRepository {
async fn find_by_id<'e, E>(executor: E, id: i64) -> Result<Option<RuntimeVersion>>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let row = sqlx::query_as::<_, RuntimeVersion>(&format!(
"SELECT {} FROM runtime_version WHERE id = $1",
SELECT_COLUMNS
))
.bind(id)
.fetch_optional(executor)
.await?;
Ok(row)
}
}
#[async_trait::async_trait]
impl List for RuntimeVersionRepository {
async fn list<'e, E>(executor: E) -> Result<Vec<RuntimeVersion>>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let rows = sqlx::query_as::<_, RuntimeVersion>(&format!(
"SELECT {} FROM runtime_version ORDER BY runtime_ref ASC, version ASC",
SELECT_COLUMNS
))
.fetch_all(executor)
.await?;
Ok(rows)
}
}
#[async_trait::async_trait]
impl Create for RuntimeVersionRepository {
type CreateInput = CreateRuntimeVersionInput;
async fn create<'e, E>(executor: E, input: Self::CreateInput) -> Result<RuntimeVersion>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let row = sqlx::query_as::<_, RuntimeVersion>(&format!(
r#"
INSERT INTO runtime_version (
runtime, runtime_ref, version,
version_major, version_minor, version_patch,
execution_config, distributions,
is_default, available, meta
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
RETURNING {}
"#,
SELECT_COLUMNS
))
.bind(input.runtime)
.bind(&input.runtime_ref)
.bind(&input.version)
.bind(input.version_major)
.bind(input.version_minor)
.bind(input.version_patch)
.bind(&input.execution_config)
.bind(&input.distributions)
.bind(input.is_default)
.bind(input.available)
.bind(&input.meta)
.fetch_one(executor)
.await?;
Ok(row)
}
}
#[async_trait::async_trait]
impl Update for RuntimeVersionRepository {
type UpdateInput = UpdateRuntimeVersionInput;
async fn update<'e, E>(executor: E, id: i64, input: Self::UpdateInput) -> Result<RuntimeVersion>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let mut query: QueryBuilder<Postgres> = QueryBuilder::new("UPDATE runtime_version SET ");
let mut has_updates = false;
if let Some(version) = &input.version {
query.push("version = ");
query.push_bind(version);
has_updates = true;
}
if let Some(version_major) = &input.version_major {
if has_updates {
query.push(", ");
}
query.push("version_major = ");
query.push_bind(*version_major);
has_updates = true;
}
if let Some(version_minor) = &input.version_minor {
if has_updates {
query.push(", ");
}
query.push("version_minor = ");
query.push_bind(*version_minor);
has_updates = true;
}
if let Some(version_patch) = &input.version_patch {
if has_updates {
query.push(", ");
}
query.push("version_patch = ");
query.push_bind(*version_patch);
has_updates = true;
}
if let Some(execution_config) = &input.execution_config {
if has_updates {
query.push(", ");
}
query.push("execution_config = ");
query.push_bind(execution_config);
has_updates = true;
}
if let Some(distributions) = &input.distributions {
if has_updates {
query.push(", ");
}
query.push("distributions = ");
query.push_bind(distributions);
has_updates = true;
}
if let Some(is_default) = input.is_default {
if has_updates {
query.push(", ");
}
query.push("is_default = ");
query.push_bind(is_default);
has_updates = true;
}
if let Some(available) = input.available {
if has_updates {
query.push(", ");
}
query.push("available = ");
query.push_bind(available);
has_updates = true;
}
if let Some(verified_at) = &input.verified_at {
if has_updates {
query.push(", ");
}
query.push("verified_at = ");
query.push_bind(*verified_at);
has_updates = true;
}
if let Some(meta) = &input.meta {
if has_updates {
query.push(", ");
}
query.push("meta = ");
query.push_bind(meta);
has_updates = true;
}
if !has_updates {
// Nothing to update — just fetch the current row
return Self::find_by_id(executor, id)
.await?
.ok_or_else(|| crate::Error::not_found("runtime_version", "id", id.to_string()));
}
query.push(" WHERE id = ");
query.push_bind(id);
query.push(&format!(" RETURNING {}", SELECT_COLUMNS));
let row = query
.build_query_as::<RuntimeVersion>()
.fetch_optional(executor)
.await?
.ok_or_else(|| crate::Error::not_found("runtime_version", "id", id.to_string()))?;
Ok(row)
}
}
#[async_trait::async_trait]
impl Delete for RuntimeVersionRepository {
async fn delete<'e, E>(executor: E, id: i64) -> Result<bool>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let result = sqlx::query("DELETE FROM runtime_version WHERE id = $1")
.bind(id)
.execute(executor)
.await?;
Ok(result.rows_affected() > 0)
}
}
/// Specialized queries
impl RuntimeVersionRepository {
/// Find all versions for a given runtime ID.
///
/// Returns versions ordered by major, minor, patch descending
/// (newest version first).
pub async fn find_by_runtime<'e, E>(executor: E, runtime_id: Id) -> Result<Vec<RuntimeVersion>>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let rows = sqlx::query_as::<_, RuntimeVersion>(&format!(
r#"
SELECT {}
FROM runtime_version
WHERE runtime = $1
ORDER BY version_major DESC NULLS LAST,
version_minor DESC NULLS LAST,
version_patch DESC NULLS LAST
"#,
SELECT_COLUMNS
))
.bind(runtime_id)
.fetch_all(executor)
.await?;
Ok(rows)
}
/// Find all versions for a given runtime ref (e.g., "core.python").
pub async fn find_by_runtime_ref<'e, E>(
executor: E,
runtime_ref: &str,
) -> Result<Vec<RuntimeVersion>>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let rows = sqlx::query_as::<_, RuntimeVersion>(&format!(
r#"
SELECT {}
FROM runtime_version
WHERE runtime_ref = $1
ORDER BY version_major DESC NULLS LAST,
version_minor DESC NULLS LAST,
version_patch DESC NULLS LAST
"#,
SELECT_COLUMNS
))
.bind(runtime_ref)
.fetch_all(executor)
.await?;
Ok(rows)
}
/// Find all available versions for a given runtime ID.
///
/// Only returns versions where `available = true`.
pub async fn find_available_by_runtime<'e, E>(
executor: E,
runtime_id: Id,
) -> Result<Vec<RuntimeVersion>>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let rows = sqlx::query_as::<_, RuntimeVersion>(&format!(
r#"
SELECT {}
FROM runtime_version
WHERE runtime = $1 AND available = TRUE
ORDER BY version_major DESC NULLS LAST,
version_minor DESC NULLS LAST,
version_patch DESC NULLS LAST
"#,
SELECT_COLUMNS
))
.bind(runtime_id)
.fetch_all(executor)
.await?;
Ok(rows)
}
/// Find the default version for a given runtime ID.
///
/// Returns `None` if no version is marked as default.
pub async fn find_default_by_runtime<'e, E>(
executor: E,
runtime_id: Id,
) -> Result<Option<RuntimeVersion>>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let row = sqlx::query_as::<_, RuntimeVersion>(&format!(
r#"
SELECT {}
FROM runtime_version
WHERE runtime = $1 AND is_default = TRUE
LIMIT 1
"#,
SELECT_COLUMNS
))
.bind(runtime_id)
.fetch_optional(executor)
.await?;
Ok(row)
}
/// Find a specific version by runtime ID and version string.
pub async fn find_by_runtime_and_version<'e, E>(
executor: E,
runtime_id: Id,
version: &str,
) -> Result<Option<RuntimeVersion>>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let row = sqlx::query_as::<_, RuntimeVersion>(&format!(
r#"
SELECT {}
FROM runtime_version
WHERE runtime = $1 AND version = $2
"#,
SELECT_COLUMNS
))
.bind(runtime_id)
.bind(version)
.fetch_optional(executor)
.await?;
Ok(row)
}
/// Clear the `is_default` flag on all versions for a runtime.
///
/// Useful before setting a new default version.
pub async fn clear_default_for_runtime<'e, E>(executor: E, runtime_id: Id) -> Result<u64>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let result = sqlx::query(
"UPDATE runtime_version SET is_default = FALSE WHERE runtime = $1 AND is_default = TRUE",
)
.bind(runtime_id)
.execute(executor)
.await?;
Ok(result.rows_affected())
}
/// Mark a version's availability and update the verification timestamp.
pub async fn set_availability<'e, E>(executor: E, id: Id, available: bool) -> Result<bool>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let result = sqlx::query(
"UPDATE runtime_version SET available = $1, verified_at = NOW() WHERE id = $2",
)
.bind(available)
.bind(id)
.execute(executor)
.await?;
Ok(result.rows_affected() > 0)
}
/// Delete all versions for a given runtime ID.
pub async fn delete_by_runtime<'e, E>(executor: E, runtime_id: Id) -> Result<u64>
where
E: Executor<'e, Database = Postgres> + 'e,
{
let result = sqlx::query("DELETE FROM runtime_version WHERE runtime = $1")
.bind(runtime_id)
.execute(executor)
.await?;
Ok(result.rows_affected())
}
}