ferrum-orm 0.1.15__tar.gz → 0.1.16__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/Cargo.lock +4 -4
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/Cargo.toml +1 -1
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/PKG-INFO +1 -1
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/src/emit.rs +85 -3
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/pyproject.toml +1 -1
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/__init__.py +1 -1
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/LICENSE +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/README.md +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/Cargo.toml +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/benches/hydrate.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/src/compile/mod.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/src/error.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/src/hydrate/mod.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/src/ir/metadata.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/src/ir/mod.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/src/lib.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-core/src/migrate/mod.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-pyo3/Cargo.toml +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-pyo3/src/lib.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/Cargo.toml +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/benches/compile.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/src/dialect.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/src/fts/mod.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/src/fts/mssql.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/src/fts/mysql.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/src/fts/postgres.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/src/fts/sqlite.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/crates/ferrum-sql/src/lib.rs +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/_native.pyi +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/__init__.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/app.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/bootstrap.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/init.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/inspectdb_cmd.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/makemigrations_cmd.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/migrate_cmd.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/migrations_cmd.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/resetdb_cmd.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/revert_cmd.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/showmigrations_cmd.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/cli/sqlmigrate_cmd.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/config.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/connection.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/contrib/__init__.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/contrib/fastapi.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/drivers/__init__.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/drivers/mssql.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/drivers/mysql.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/drivers/postgres.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/drivers/protocol.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/drivers/sqlite.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/drivers/streaming.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/echo.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/errors.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/expressions.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/ext/__init__.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/ext/fts.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/ext/pgvector.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/hooks.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/__init__.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/base.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/drift.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/fts/__init__.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/fts/mssql.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/fts/mysql.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/fts/postgres.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/fts/sqlite.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/gates.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/introspect.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/ledger.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/loader.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/operations.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/orchestrator.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/migrations/tokens.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/models.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/observability.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/py.typed +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/queryset.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/registry.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/relations.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/runtime.py +0 -0
- {ferrum_orm-0.1.15 → ferrum_orm-0.1.16}/python/ferrum/session.py +0 -0
|
@@ -223,7 +223,7 @@ checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
|
|
223
223
|
|
|
224
224
|
[[package]]
|
|
225
225
|
name = "ferrum-core"
|
|
226
|
-
version = "0.1.
|
|
226
|
+
version = "0.1.16"
|
|
227
227
|
dependencies = [
|
|
228
228
|
"criterion",
|
|
229
229
|
"proptest",
|
|
@@ -234,7 +234,7 @@ dependencies = [
|
|
|
234
234
|
|
|
235
235
|
[[package]]
|
|
236
236
|
name = "ferrum-migrate"
|
|
237
|
-
version = "0.1.
|
|
237
|
+
version = "0.1.16"
|
|
238
238
|
dependencies = [
|
|
239
239
|
"ferrum-core",
|
|
240
240
|
"serde",
|
|
@@ -243,7 +243,7 @@ dependencies = [
|
|
|
243
243
|
|
|
244
244
|
[[package]]
|
|
245
245
|
name = "ferrum-pyo3"
|
|
246
|
-
version = "0.1.
|
|
246
|
+
version = "0.1.16"
|
|
247
247
|
dependencies = [
|
|
248
248
|
"ferrum-core",
|
|
249
249
|
"ferrum-sql",
|
|
@@ -255,7 +255,7 @@ dependencies = [
|
|
|
255
255
|
|
|
256
256
|
[[package]]
|
|
257
257
|
name = "ferrum-sql"
|
|
258
|
-
version = "0.1.
|
|
258
|
+
version = "0.1.16"
|
|
259
259
|
dependencies = [
|
|
260
260
|
"criterion",
|
|
261
261
|
"ferrum-core",
|
|
@@ -1219,6 +1219,11 @@ fn filter_clause(
|
|
|
1219
1219
|
/// `UPDATE … FROM (VALUES …)` requires explicit casts so `PostgreSQL` can infer
|
|
1220
1220
|
/// the correct column types when the VALUES clause contains multiple rows.
|
|
1221
1221
|
/// The cast is appended to the placeholder, e.g. `$1::bigint`, `$2::text`.
|
|
1222
|
+
///
|
|
1223
|
+
/// The cast must be assignment-compatible with the DDL column type, and for PK
|
|
1224
|
+
/// columns it must match exactly: the join predicate `t.pk = v.pk` resolves an
|
|
1225
|
+
/// operator rather than an assignment cast, so a `uuid` column compared against
|
|
1226
|
+
/// a `text` VALUES column fails with `UndefinedFunction` (42883).
|
|
1222
1227
|
fn postgres_value_cast(
|
|
1223
1228
|
field_type: ferrum_core::ir::metadata::FieldType,
|
|
1224
1229
|
placeholder: &str,
|
|
@@ -1226,8 +1231,11 @@ fn postgres_value_cast(
|
|
|
1226
1231
|
use ferrum_core::ir::metadata::FieldType;
|
|
1227
1232
|
let cast = match field_type {
|
|
1228
1233
|
FieldType::Int | FieldType::BigInt => "bigint",
|
|
1229
|
-
FieldType::Float
|
|
1230
|
-
FieldType::
|
|
1234
|
+
FieldType::Float => "double precision",
|
|
1235
|
+
FieldType::Decimal => "numeric",
|
|
1236
|
+
FieldType::Text | FieldType::Enum => "text",
|
|
1237
|
+
FieldType::Uuid => "uuid",
|
|
1238
|
+
FieldType::TsVector => "tsvector",
|
|
1231
1239
|
FieldType::Bool => "boolean",
|
|
1232
1240
|
FieldType::Datetime => "timestamptz",
|
|
1233
1241
|
FieldType::Date => "date",
|
|
@@ -1235,7 +1243,8 @@ fn postgres_value_cast(
|
|
|
1235
1243
|
FieldType::Json => "jsonb",
|
|
1236
1244
|
FieldType::Bytes => "bytea",
|
|
1237
1245
|
FieldType::Vector => "vector",
|
|
1238
|
-
FieldType::ArrayText
|
|
1246
|
+
FieldType::ArrayText => "text[]",
|
|
1247
|
+
FieldType::ArrayUuid => "uuid[]",
|
|
1239
1248
|
FieldType::ArrayInt => "bigint[]",
|
|
1240
1249
|
FieldType::ArrayFloat => "double precision[]",
|
|
1241
1250
|
};
|
|
@@ -2112,6 +2121,79 @@ mod tests {
|
|
|
2112
2121
|
assert!(matches!(err, CompileError::MalformedIr { .. }));
|
|
2113
2122
|
}
|
|
2114
2123
|
|
|
2124
|
+
/// Every VALUES placeholder must carry the cast of its DDL column type.
|
|
2125
|
+
/// A `uuid` PK cast to `text` made `t.id = v.id` resolve `uuid = text`,
|
|
2126
|
+
/// which `PostgreSQL` rejects with `UndefinedFunction` (42883); `uuid[]` and
|
|
2127
|
+
/// `tsvector` columns failed the SET assignment for the same reason.
|
|
2128
|
+
#[test]
|
|
2129
|
+
fn bulk_update_casts_match_column_types() {
|
|
2130
|
+
let field = |name: &str, field_type: FieldType| FieldMeta {
|
|
2131
|
+
name: name.into(),
|
|
2132
|
+
column_name: name.into(),
|
|
2133
|
+
field_type,
|
|
2134
|
+
allowed_operators: vec!["eq".into()],
|
|
2135
|
+
nullable: true,
|
|
2136
|
+
vector_dimensions: None,
|
|
2137
|
+
fts_config: None,
|
|
2138
|
+
fts_source_columns: None,
|
|
2139
|
+
};
|
|
2140
|
+
let meta = ModelMetadata {
|
|
2141
|
+
model_name: "Ticket".into(),
|
|
2142
|
+
table_name: "tickets".into(),
|
|
2143
|
+
fields: vec![
|
|
2144
|
+
field("id", FieldType::Uuid),
|
|
2145
|
+
field("tags", FieldType::ArrayUuid),
|
|
2146
|
+
field("search", FieldType::TsVector),
|
|
2147
|
+
field("amount", FieldType::Decimal),
|
|
2148
|
+
],
|
|
2149
|
+
pk_index: 0,
|
|
2150
|
+
pk_fields: vec![0],
|
|
2151
|
+
full_text_indexes: vec![],
|
|
2152
|
+
};
|
|
2153
|
+
let field_ref = |name: &str, index: usize| FieldRef {
|
|
2154
|
+
name: name.into(),
|
|
2155
|
+
index,
|
|
2156
|
+
};
|
|
2157
|
+
let ir = QuerySetIR {
|
|
2158
|
+
version: IR_VERSION,
|
|
2159
|
+
model_name: "Ticket".into(),
|
|
2160
|
+
operation: Operation::BulkUpdate {
|
|
2161
|
+
pk_fields: vec![field_ref("id", 0)],
|
|
2162
|
+
fields: vec![
|
|
2163
|
+
field_ref("tags", 1),
|
|
2164
|
+
field_ref("search", 2),
|
|
2165
|
+
field_ref("amount", 3),
|
|
2166
|
+
],
|
|
2167
|
+
rows: vec![ferrum_core::ir::BulkUpdateRow {
|
|
2168
|
+
pk_values: vec![BindValue::Text(
|
|
2169
|
+
"00000000-0000-0000-0000-000000000001".into(),
|
|
2170
|
+
)],
|
|
2171
|
+
values: vec![
|
|
2172
|
+
BindValue::TextArray(vec![]),
|
|
2173
|
+
BindValue::Text("lexeme".into()),
|
|
2174
|
+
BindValue::Text("1.005".into()),
|
|
2175
|
+
],
|
|
2176
|
+
}],
|
|
2177
|
+
},
|
|
2178
|
+
filters: vec![],
|
|
2179
|
+
order_by: vec![],
|
|
2180
|
+
limit: None,
|
|
2181
|
+
offset: None,
|
|
2182
|
+
vector_order_by: None,
|
|
2183
|
+
text_rank_by: None,
|
|
2184
|
+
predicate: None,
|
|
2185
|
+
distinct: false,
|
|
2186
|
+
exists: false,
|
|
2187
|
+
joins: vec![],
|
|
2188
|
+
aggregation: None,
|
|
2189
|
+
};
|
|
2190
|
+
let q = emit_bulk_update(Dialect::Postgres, &meta, &ir).unwrap();
|
|
2191
|
+
assert!(q.sql_text.contains("$1::uuid,"), "{}", q.sql_text);
|
|
2192
|
+
assert!(q.sql_text.contains("$2::uuid[]"), "{}", q.sql_text);
|
|
2193
|
+
assert!(q.sql_text.contains("$3::tsvector"), "{}", q.sql_text);
|
|
2194
|
+
assert!(q.sql_text.contains("$4::numeric"), "{}", q.sql_text);
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2115
2197
|
// ── MessagePack wire-format round-trip ───────────────────────────────────
|
|
2116
2198
|
|
|
2117
2199
|
/// IR + metadata `MessagePack`-encoded (NAMED) decode back into the same serde
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|