+65
-4
api/src/graphql/schema_builder.rs
+65
-4
api/src/graphql/schema_builder.rs
···
2504
2504
let type_name = nsid_to_type_name(nsid);
2505
2505
2506
2506
// Add create mutation
2507
-
mutation = add_create_mutation(mutation, &type_name, nsid, database.clone(), slice_uri.clone());
2507
+
mutation = add_create_mutation(mutation, &type_name, nsid, &fields, database.clone(), slice_uri.clone());
2508
2508
2509
2509
// Add update mutation
2510
-
mutation = add_update_mutation(mutation, &type_name, nsid, database.clone(), slice_uri.clone());
2510
+
mutation = add_update_mutation(mutation, &type_name, nsid, &fields, database.clone(), slice_uri.clone());
2511
2511
2512
2512
// Add delete mutation
2513
2513
mutation = add_delete_mutation(mutation, &type_name, nsid, database.clone(), slice_uri.clone());
···
3157
3157
input
3158
3158
}
3159
3159
3160
+
/// Transforms blob fields in record data from GraphQL format to AT Protocol format
3161
+
///
3162
+
/// GraphQL format: `{ref: "bafyrei...", mimeType: "...", size: 123}`
3163
+
/// AT Protocol format: `{ref: {$link: "bafyrei..."}, mimeType: "...", size: 123}`
3164
+
fn transform_blob_fields_for_atproto(
3165
+
mut data: serde_json::Value,
3166
+
fields: &[GraphQLField],
3167
+
) -> serde_json::Value {
3168
+
if let serde_json::Value::Object(ref mut map) = data {
3169
+
for field in fields {
3170
+
if let Some(field_value) = map.get_mut(&field.name) {
3171
+
match &field.field_type {
3172
+
GraphQLType::Blob => {
3173
+
// Transform single blob field
3174
+
if let Some(blob_obj) = field_value.as_object_mut() {
3175
+
// Check if ref is a string (GraphQL format)
3176
+
if let Some(serde_json::Value::String(cid)) = blob_obj.get("ref") {
3177
+
// Transform to {$link: "cid"} (AT Protocol format)
3178
+
let link_obj = serde_json::json!({
3179
+
"$link": cid
3180
+
});
3181
+
blob_obj.insert("ref".to_string(), link_obj);
3182
+
}
3183
+
}
3184
+
}
3185
+
GraphQLType::Array(inner) if matches!(inner.as_ref(), GraphQLType::Blob) => {
3186
+
// Transform array of blobs
3187
+
if let Some(arr) = field_value.as_array_mut() {
3188
+
for blob_value in arr {
3189
+
if let Some(blob_obj) = blob_value.as_object_mut() {
3190
+
if let Some(serde_json::Value::String(cid)) = blob_obj.get("ref") {
3191
+
let link_obj = serde_json::json!({
3192
+
"$link": cid
3193
+
});
3194
+
blob_obj.insert("ref".to_string(), link_obj);
3195
+
}
3196
+
}
3197
+
}
3198
+
}
3199
+
}
3200
+
_ => {} // Other field types don't need transformation
3201
+
}
3202
+
}
3203
+
}
3204
+
}
3205
+
3206
+
data
3207
+
}
3208
+
3160
3209
/// Adds a create mutation for a collection
3161
3210
fn add_create_mutation(
3162
3211
mutation: Object,
3163
3212
type_name: &str,
3164
3213
nsid: &str,
3214
+
fields: &[GraphQLField],
3165
3215
database: Database,
3166
3216
slice_uri: String,
3167
3217
) -> Object {
3168
3218
let mutation_name = format!("create{}", type_name);
3169
3219
let nsid = nsid.to_string();
3170
3220
let nsid_clone = nsid.clone();
3221
+
let fields = fields.to_vec();
3171
3222
3172
3223
mutation.field(
3173
3224
Field::new(
···
3177
3228
let db = database.clone();
3178
3229
let slice = slice_uri.clone();
3179
3230
let collection = nsid.clone();
3231
+
let fields = fields.clone();
3180
3232
3181
3233
FieldFuture::new(async move {
3182
3234
// Get GraphQL context which contains auth info
···
3192
3244
.ok_or_else(|| Error::new("Missing input argument"))?;
3193
3245
3194
3246
// Convert GraphQL value to JSON using deserialize
3195
-
let record_data: serde_json::Value = input.deserialize()
3247
+
let mut record_data: serde_json::Value = input.deserialize()
3196
3248
.map_err(|e| Error::new(format!("Failed to deserialize input: {:?}", e)))?;
3249
+
3250
+
// Transform blob fields from GraphQL format (ref: "cid") to AT Protocol format (ref: {$link: "cid"})
3251
+
record_data = transform_blob_fields_for_atproto(record_data, &fields);
3197
3252
3198
3253
// Optional rkey argument
3199
3254
let rkey = ctx.args.get("rkey")
···
3322
3377
mutation: Object,
3323
3378
type_name: &str,
3324
3379
nsid: &str,
3380
+
fields: &[GraphQLField],
3325
3381
database: Database,
3326
3382
slice_uri: String,
3327
3383
) -> Object {
3328
3384
let mutation_name = format!("update{}", type_name);
3329
3385
let nsid = nsid.to_string();
3330
3386
let nsid_clone = nsid.clone();
3387
+
let fields = fields.to_vec();
3331
3388
3332
3389
mutation.field(
3333
3390
Field::new(
···
3337
3394
let db = database.clone();
3338
3395
let slice = slice_uri.clone();
3339
3396
let collection = nsid.clone();
3397
+
let fields = fields.clone();
3340
3398
3341
3399
FieldFuture::new(async move {
3342
3400
// Get GraphQL context which contains auth info
···
3358
3416
.ok_or_else(|| Error::new("Missing input argument"))?;
3359
3417
3360
3418
// Convert GraphQL value to JSON using deserialize
3361
-
let record_data: serde_json::Value = input.deserialize()
3419
+
let mut record_data: serde_json::Value = input.deserialize()
3362
3420
.map_err(|e| Error::new(format!("Failed to deserialize input: {:?}", e)))?;
3421
+
3422
+
// Transform blob fields from GraphQL format (ref: "cid") to AT Protocol format (ref: {$link: "cid"})
3423
+
record_data = transform_blob_fields_for_atproto(record_data, &fields);
3363
3424
3364
3425
// Verify OAuth token and get user info
3365
3426
let user_info = crate::auth::verify_oauth_token_cached(