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
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ name = "cocoindex_engine"
crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.23.5" }
pyo3 = { version = "0.23.5", features = ["chrono"] }
anyhow = { version = "1.0.97", features = ["std"] }
async-trait = "0.1.88"
axum = "0.7.9"
Expand All @@ -25,7 +25,12 @@ log = "0.4.26"
regex = "1.11.1"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
sqlx = { version = "0.8.3", features = ["chrono", "postgres", "runtime-tokio", "uuid"] }
sqlx = { version = "0.8.3", features = [
"chrono",
"postgres",
"runtime-tokio",
"uuid",
] }
tokio = { version = "1.44.1", features = [
"macros",
"rt-multi-thread",
Expand Down
9 changes: 9 additions & 0 deletions python/cocoindex/typing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import typing
import collections
import dataclasses
import datetime
import types
import inspect
import uuid
Expand All @@ -26,6 +27,8 @@ def __init__(self, key: str, value: Any):
Float64 = Annotated[float, TypeKind('Float64')]
Range = Annotated[tuple[int, int], TypeKind('Range')]
Json = Annotated[Any, TypeKind('Json')]
LocalDateTime = Annotated[datetime.datetime, TypeKind('LocalDateTime')]
OffsetDateTime = Annotated[datetime.datetime, TypeKind('OffsetDateTime')]

COLLECTION_TYPES = ('Table', 'List')

Expand Down Expand Up @@ -133,6 +136,12 @@ def analyze_type_info(t) -> AnalyzedTypeInfo:
kind = 'Float64'
elif t is uuid.UUID:
kind = 'Uuid'
elif t is datetime.date:
kind = 'Date'
elif t is datetime.time:
kind = 'Time'
elif t is datetime.datetime:
kind = 'OffsetDateTime'
else:
raise ValueError(f"type unsupported yet: {t}")

Expand Down
49 changes: 44 additions & 5 deletions src/base/json_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ pub struct ToJsonSchemaOptions {
/// Use union type (with `null`) for optional fields instead.
/// Models like OpenAI will reject the schema if a field is not required.
pub fields_always_required: bool,

/// If true, the JSON schema supports the `format` keyword.
pub supports_format: bool,
}

pub trait ToJsonSchema {
Expand Down Expand Up @@ -49,15 +52,51 @@ impl ToJsonSchema for schema::BasicValueType {
max_items: Some(2),
..Default::default()
}));
schema
.metadata
.get_or_insert_with(Default::default)
.description =
schema.metadata.get_or_insert_default().description =
Some("A range, start pos (inclusive), end pos (exclusive).".to_string());
}
schema::BasicValueType::Uuid => {
schema.instance_type = Some(SingleOrVec::Single(Box::new(InstanceType::String)));
schema.format = Some("uuid".to_string());
if options.supports_format {
schema.format = Some("uuid".to_string());
} else {
schema.metadata.get_or_insert_default().description =
Some("A UUID, e.g. 123e4567-e89b-12d3-a456-426614174000".to_string());
}
}
schema::BasicValueType::Date => {
schema.instance_type = Some(SingleOrVec::Single(Box::new(InstanceType::String)));
if options.supports_format {
schema.format = Some("date".to_string());
} else {
schema.metadata.get_or_insert_default().description =
Some("A date, e.g. 2025-03-27".to_string());
}
}
schema::BasicValueType::Time => {
schema.instance_type = Some(SingleOrVec::Single(Box::new(InstanceType::String)));
if options.supports_format {
schema.format = Some("time".to_string());
} else {
schema.metadata.get_or_insert_default().description =
Some("A time, e.g. 13:32:12".to_string());
}
}
schema::BasicValueType::LocalDateTime => {
schema.instance_type = Some(SingleOrVec::Single(Box::new(InstanceType::String)));
if options.supports_format {
schema.format = Some("date-time".to_string());
}
schema.metadata.get_or_insert_default().description =
Some("Date time without timezone offset, e.g. 2025-03-27T13:32:12".to_string());
}
schema::BasicValueType::OffsetDateTime => {
schema.instance_type = Some(SingleOrVec::Single(Box::new(InstanceType::String)));
if options.supports_format {
schema.format = Some("date-time".to_string());
}
schema.metadata.get_or_insert_default().description =
Some("Date time with timezone offset in RFC3339, e.g. 2025-03-27T13:32:12Z, 2025-03-27T07:32:12.313-06:00".to_string());
}
schema::BasicValueType::Json => {
// Can be any value. No type constraint.
Expand Down
16 changes: 16 additions & 0 deletions src/base/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ pub enum BasicValueType {
/// A UUID.
Uuid,

/// Date (without time within the current day).
Date,

/// Time of the day.
Time,

/// Local date and time, without timezone.
LocalDateTime,

/// Date and time with timezone.
OffsetDateTime,

/// A JSON value.
Json,

Expand All @@ -56,6 +68,10 @@ impl std::fmt::Display for BasicValueType {
BasicValueType::Float64 => write!(f, "float64"),
BasicValueType::Range => write!(f, "range"),
BasicValueType::Uuid => write!(f, "uuid"),
BasicValueType::Date => write!(f, "date"),
BasicValueType::Time => write!(f, "time"),
BasicValueType::LocalDateTime => write!(f, "local_datetime"),
BasicValueType::OffsetDateTime => write!(f, "offset_datetime"),
BasicValueType::Json => write!(f, "json"),
BasicValueType::Vector(s) => write!(
f,
Expand Down
Loading