package sqlite import ( "context" "database/sql" "errors" "time" "cmroubao/backend-api/internal/domain" "cmroubao/backend-api/internal/usecase" ) func (store *Store) CreateFreightSync( ctx context.Context, run domain.FreightSyncRun, idempotencyKey string, requestSHA256 string, ) (domain.FreightSyncRun, bool, error) { tx, err := store.db.BeginTx(ctx, nil) if err != nil { return domain.FreightSyncRun{}, false, repositoryFailure(err) } defer tx.Rollback() existing, err := scanFreightSync(tx.QueryRowContext( ctx, freightSyncSelect+` WHERE creator_subject = ? AND idempotency_key = ?`, run.CreatorSubject, idempotencyKey, )) if err == nil { var storedHash string if err := tx.QueryRowContext( ctx, `SELECT request_sha256 FROM erp_sync_runs WHERE creator_subject = ? AND idempotency_key = ?`, run.CreatorSubject, idempotencyKey, ).Scan(&storedHash); err != nil { return domain.FreightSyncRun{}, false, repositoryFailure(err) } if storedHash != requestSHA256 { return domain.FreightSyncRun{}, false, usecase.ErrIdempotencyConflict } return existing, false, nil } if !errors.Is(err, sql.ErrNoRows) { return domain.FreightSyncRun{}, false, repositoryFailure(err) } _, err = tx.ExecContext( ctx, `INSERT INTO erp_sync_runs ( id, creator_subject, created_by_user_id, mode, order_number, created_from, created_to, watermark_through, query_sha256, idempotency_key, request_sha256, status, order_count, item_count, created_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, ?)`, run.ID, run.CreatorSubject, run.CreatedByUserID, run.Mode, nullableFreightSyncValue(run.OrderNumber), nullableFreightSyncValue(run.CreatedFrom), nullableFreightSyncValue(run.CreatedTo), nullableTimestamp(run.WatermarkThrough), run.QuerySHA256, idempotencyKey, requestSHA256, run.Status, formatTimestamp(run.CreatedAt), ) if err != nil { return domain.FreightSyncRun{}, false, repositoryFailure(err) } if err := tx.Commit(); err != nil { return domain.FreightSyncRun{}, false, repositoryFailure(err) } return run, true, nil } func (store *Store) StartFreightSync( ctx context.Context, runID string, startedAt time.Time, ) error { result, err := store.db.ExecContext( ctx, `UPDATE erp_sync_runs SET status = 'RUNNING', started_at = ? WHERE id = ? AND status = 'PENDING'`, formatTimestamp(startedAt), runID, ) if err != nil { return repositoryFailure(err) } changed, err := result.RowsAffected() if err != nil { return repositoryFailure(err) } if changed != 1 { return usecase.ErrTaskStateConflict } return nil } func (store *Store) CompleteFreightSync( ctx context.Context, run domain.FreightSyncRun, batch domain.FreightImportBatch, finishedAt time.Time, ) error { return store.completeFreightSync(ctx, run, batch, nil, finishedAt) } func (store *Store) CompleteFreightDateSync( ctx context.Context, run domain.FreightSyncRun, batch domain.FreightImportBatch, watermarkThrough time.Time, finishedAt time.Time, ) error { return store.completeFreightSync( ctx, run, batch, &watermarkThrough, finishedAt, ) } func (store *Store) completeFreightSync( ctx context.Context, run domain.FreightSyncRun, batch domain.FreightImportBatch, watermarkThrough *time.Time, finishedAt time.Time, ) error { tx, err := store.db.BeginTx(ctx, nil) if err != nil { return repositoryFailure(err) } defer tx.Rollback() var status string if err := tx.QueryRowContext( ctx, `SELECT status FROM erp_sync_runs WHERE id = ?`, run.ID, ).Scan(&status); err != nil { if errors.Is(err, sql.ErrNoRows) { return usecase.ErrRepositoryNotFound } return repositoryFailure(err) } if status != string(domain.FreightSyncRunning) { return usecase.ErrTaskStateConflict } itemCount := 0 for _, order := range batch.Orders { orderID, err := upsertFreightOrder( ctx, tx, run, order, finishedAt, ) if err != nil { return err } if _, err := tx.ExecContext( ctx, `UPDATE freight_order_items SET is_present = 0, last_sync_run_id = ?, updated_at = ? WHERE freight_order_id = ?`, run.ID, formatTimestamp(finishedAt), orderID, ); err != nil { return repositoryFailure(err) } for _, item := range order.Items { if err := upsertFreightOrderItem( ctx, tx, run.ID, orderID, item, finishedAt, ); err != nil { return err } itemCount++ } } result, err := tx.ExecContext( ctx, `UPDATE erp_sync_runs SET status = 'SUCCEEDED', error_code = NULL, order_count = ?, item_count = ?, finished_at = ? WHERE id = ? AND status = 'RUNNING'`, len(batch.Orders), itemCount, formatTimestamp(finishedAt), run.ID, ) if err != nil { return repositoryFailure(err) } changed, err := result.RowsAffected() if err != nil { return repositoryFailure(err) } if changed != 1 { return usecase.ErrTaskStateConflict } if watermarkThrough != nil { if _, err := tx.ExecContext( ctx, `INSERT INTO erp_sync_watermarks ( creator_subject, source_system, last_successful_to, last_successful_run_id, updated_at ) VALUES (?, 'SHUNYUNBAO', ?, ?, ?) ON CONFLICT (creator_subject, source_system) DO UPDATE SET last_successful_to = excluded.last_successful_to, last_successful_run_id = excluded.last_successful_run_id, updated_at = excluded.updated_at WHERE julianday(erp_sync_watermarks.last_successful_to) < julianday(excluded.last_successful_to)`, run.CreatorSubject, formatTimestamp(*watermarkThrough), run.ID, formatTimestamp(finishedAt), ); err != nil { return repositoryFailure(err) } } if err := tx.Commit(); err != nil { return repositoryFailure(err) } return nil } func upsertFreightOrder( ctx context.Context, tx *sql.Tx, run domain.FreightSyncRun, order domain.FreightImportOrder, now time.Time, ) (string, error) { _, err := tx.ExecContext( ctx, `INSERT INTO freight_orders ( id, creator_subject, source_system, external_stock_id, source_code, platform_order_no, shop_name, source_created_at, order_status, purchase_status, is_canceled, canonical_sha256, revision, first_sync_run_id, last_sync_run_id, created_at, updated_at ) VALUES (?, ?, 'SHUNYUNBAO', ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?) ON CONFLICT (creator_subject, source_system, external_stock_id) DO UPDATE SET source_code = excluded.source_code, platform_order_no = excluded.platform_order_no, shop_name = excluded.shop_name, source_created_at = excluded.source_created_at, order_status = excluded.order_status, purchase_status = excluded.purchase_status, is_canceled = excluded.is_canceled, revision = CASE WHEN freight_orders.canonical_sha256 != excluded.canonical_sha256 THEN freight_orders.revision + 1 ELSE freight_orders.revision END, canonical_sha256 = excluded.canonical_sha256, last_sync_run_id = excluded.last_sync_run_id, updated_at = excluded.updated_at`, order.ID, run.CreatorSubject, order.ExternalStockID, order.SourceCode, nullableString(order.PlatformOrderNo), nullableString(order.ShopName), nullableTimestamp(order.SourceCreatedAt), nullableString(order.OrderStatus), nullableString(order.PurchaseStatus), nullableBool(order.IsCanceled), order.CanonicalSHA256, run.ID, run.ID, formatTimestamp(now), formatTimestamp(now), ) if err != nil { return "", repositoryFailure(err) } var orderID string if err := tx.QueryRowContext( ctx, `SELECT id FROM freight_orders WHERE creator_subject = ? AND source_system = 'SHUNYUNBAO' AND external_stock_id = ?`, run.CreatorSubject, order.ExternalStockID, ).Scan(&orderID); err != nil { return "", repositoryFailure(err) } return orderID, nil } func upsertFreightOrderItem( ctx context.Context, tx *sql.Tx, runID, orderID string, item domain.FreightImportItem, now time.Time, ) error { _, err := tx.ExecContext( ctx, `INSERT INTO freight_order_items ( id, freight_order_id, external_item_id, title, product_spec, sku, quantity, product_thumb_ref, original_unit_price_minor, original_currency, purchase_status, canonical_sha256, revision, is_present, first_sync_run_id, last_sync_run_id, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 1, ?, ?, ?, ?) ON CONFLICT (freight_order_id, external_item_id) DO UPDATE SET title = excluded.title, product_spec = excluded.product_spec, sku = excluded.sku, quantity = excluded.quantity, product_thumb_ref = excluded.product_thumb_ref, original_unit_price_minor = excluded.original_unit_price_minor, original_currency = excluded.original_currency, purchase_status = excluded.purchase_status, revision = CASE WHEN freight_order_items.canonical_sha256 != excluded.canonical_sha256 THEN freight_order_items.revision + 1 ELSE freight_order_items.revision END, canonical_sha256 = excluded.canonical_sha256, is_present = 1, last_sync_run_id = excluded.last_sync_run_id, updated_at = excluded.updated_at`, item.ID, orderID, item.ExternalItemID, item.Title, item.ProductSpec, item.SKU, nullableFreightQuantity(item.Quantity), nullableString(item.ProductThumbRef), nullableInt64(item.OriginalUnitPriceMinor), item.OriginalCurrency, nullableString(item.PurchaseStatus), item.CanonicalSHA256, runID, runID, formatTimestamp(now), formatTimestamp(now), ) if err != nil { return repositoryFailure(err) } return nil } func (store *Store) FailFreightSync( ctx context.Context, runID, errorCode string, finishedAt time.Time, ) error { result, err := store.db.ExecContext( ctx, `UPDATE erp_sync_runs SET status = 'FAILED', error_code = ?, finished_at = ? WHERE id = ? AND status IN ('PENDING', 'RUNNING')`, errorCode, formatTimestamp(finishedAt), runID, ) if err != nil { return repositoryFailure(err) } changed, err := result.RowsAffected() if err != nil { return repositoryFailure(err) } if changed != 1 { return usecase.ErrTaskStateConflict } return nil } func (store *Store) RecoverFreightSyncs( ctx context.Context, finishedAt time.Time, ) (int64, error) { result, err := store.db.ExecContext( ctx, `UPDATE erp_sync_runs SET status = 'FAILED', error_code = 'PROCESS_INTERRUPTED', finished_at = ? WHERE status IN ('PENDING', 'RUNNING')`, formatTimestamp(finishedAt), ) if err != nil { return 0, repositoryFailure(err) } changed, err := result.RowsAffected() if err != nil { return 0, repositoryFailure(err) } return changed, nil } func (store *Store) GetFreightSync( ctx context.Context, creatorSubject, runID string, ) (domain.FreightSyncRun, error) { run, err := scanFreightSync(store.db.QueryRowContext( ctx, freightSyncSelect+` WHERE creator_subject = ? AND id = ?`, creatorSubject, runID, )) if errors.Is(err, sql.ErrNoRows) { return domain.FreightSyncRun{}, usecase.ErrRepositoryNotFound } if err != nil { return domain.FreightSyncRun{}, repositoryFailure(err) } return run, nil } func (store *Store) GetFreightSyncWatermark( ctx context.Context, creatorSubject string, ) (*domain.FreightSyncWatermark, error) { var watermark domain.FreightSyncWatermark var lastSuccessfulTo, updatedAt string err := store.db.QueryRowContext( ctx, `SELECT creator_subject, source_system, last_successful_to, last_successful_run_id, updated_at FROM erp_sync_watermarks WHERE creator_subject = ? AND source_system = 'SHUNYUNBAO'`, creatorSubject, ).Scan( &watermark.CreatorSubject, &watermark.SourceSystem, &lastSuccessfulTo, &watermark.LastSuccessfulRunID, &updatedAt, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil } if err != nil { return nil, repositoryFailure(err) } watermark.LastSuccessfulTo, err = parseTimestamp(lastSuccessfulTo) if err != nil { return nil, repositoryFailure(err) } watermark.UpdatedAt, err = parseTimestamp(updatedAt) if err != nil { return nil, repositoryFailure(err) } return &watermark, nil } func (store *Store) ListFreightOrders( ctx context.Context, creatorSubject string, limit int, ) ([]domain.FreightOrder, error) { rows, err := store.db.QueryContext( ctx, freightOrderSelect+` WHERE freight_orders.creator_subject = ? ORDER BY freight_orders.updated_at DESC, freight_orders.id DESC LIMIT ?`, creatorSubject, limit, ) if err != nil { return nil, repositoryFailure(err) } orders := make([]domain.FreightOrder, 0) for rows.Next() { order, err := scanFreightOrder(rows) if err != nil { rows.Close() return nil, repositoryFailure(err) } orders = append(orders, order) } if err := rows.Err(); err != nil { rows.Close() return nil, repositoryFailure(err) } if err := rows.Close(); err != nil { return nil, repositoryFailure(err) } for index := range orders { if err := store.loadFreightOrderPreview( ctx, &orders[index], ); err != nil { return nil, err } } return orders, nil } func (store *Store) loadFreightOrderPreview( ctx context.Context, order *domain.FreightOrder, ) error { var itemID, title string var itemThumb, imageThumb, imageStatus sql.NullString err := store.db.QueryRowContext( ctx, `SELECT item.id, item.title, item.product_thumb_ref, image.product_thumb_ref, image.status FROM freight_order_items AS item LEFT JOIN freight_item_images AS image ON image.freight_order_item_id = item.id WHERE item.freight_order_id = ? AND item.is_present = 1 ORDER BY CAST(item.external_item_id AS INTEGER), item.external_item_id LIMIT 1`, order.ID, ).Scan( &itemID, &title, &itemThumb, &imageThumb, &imageStatus, ) if errors.Is(err, sql.ErrNoRows) { return nil } if err != nil { return repositoryFailure(err) } order.PreviewItemID = itemID order.PreviewTitle = title switch { case !itemThumb.Valid: order.PreviewImageStatus = domain.FreightItemImageNone case imageThumb.Valid && imageStatus.Valid && imageThumb.String == itemThumb.String: order.PreviewImageStatus = domain.FreightItemImageStatus( imageStatus.String, ) default: order.PreviewImageStatus = domain.FreightItemImagePending } return nil } func (store *Store) GetFreightOrder( ctx context.Context, creatorSubject, orderID string, ) (domain.FreightOrderDetail, error) { order, err := scanFreightOrder(store.db.QueryRowContext( ctx, freightOrderSelect+` WHERE freight_orders.creator_subject = ? AND freight_orders.id = ?`, creatorSubject, orderID, )) if errors.Is(err, sql.ErrNoRows) { return domain.FreightOrderDetail{}, usecase.ErrRepositoryNotFound } if err != nil { return domain.FreightOrderDetail{}, repositoryFailure(err) } rows, err := store.db.QueryContext( ctx, `SELECT id, freight_order_id, external_item_id, title, product_spec, sku, quantity, product_thumb_ref, original_unit_price_minor, original_currency, purchase_status, canonical_sha256, revision, is_present, first_sync_run_id, last_sync_run_id, created_at, updated_at FROM freight_order_items WHERE freight_order_id = ? AND is_present = 1 ORDER BY CAST(external_item_id AS INTEGER), external_item_id`, order.ID, ) if err != nil { return domain.FreightOrderDetail{}, repositoryFailure(err) } defer rows.Close() items := make([]domain.FreightOrderItem, 0) for rows.Next() { item, err := scanFreightOrderItem(rows) if err != nil { return domain.FreightOrderDetail{}, repositoryFailure(err) } items = append(items, item) } if err := rows.Err(); err != nil { return domain.FreightOrderDetail{}, repositoryFailure(err) } if err := store.applyFreightItemImageStatuses( ctx, order.ID, items, ); err != nil { return domain.FreightOrderDetail{}, err } return domain.FreightOrderDetail{Order: order, Items: items}, nil } func (store *Store) DeleteFreightOrder( ctx context.Context, creatorSubject, orderID string, ) ([]string, error) { tx, err := store.db.BeginTx(ctx, nil) if err != nil { return nil, repositoryFailure(err) } defer tx.Rollback() var storedOrderID string err = tx.QueryRowContext( ctx, `SELECT id FROM freight_orders WHERE creator_subject = ? AND id = ?`, creatorSubject, orderID, ).Scan(&storedOrderID) if errors.Is(err, sql.ErrNoRows) { return nil, nil } if err != nil { return nil, repositoryFailure(err) } var hasPurchaseTask int err = tx.QueryRowContext( ctx, `SELECT EXISTS ( SELECT 1 FROM freight_order_items AS item JOIN procurement_requests AS request ON request.freight_order_item_id = item.id WHERE item.freight_order_id = ? AND request.purchase_task_id IS NOT NULL )`, storedOrderID, ).Scan(&hasPurchaseTask) if err != nil { return nil, repositoryFailure(err) } if hasPurchaseTask != 0 { return nil, usecase.ErrFreightOrderHasPurchaseTask } var hasReference int err = tx.QueryRowContext( ctx, `SELECT EXISTS ( SELECT 1 FROM freight_order_items AS item JOIN procurement_requests AS request ON request.freight_order_item_id = item.id WHERE item.freight_order_id = ? AND request.reference_asset_id IS NOT NULL )`, storedOrderID, ).Scan(&hasReference) if err != nil { return nil, repositoryFailure(err) } if hasReference != 0 { return nil, usecase.ErrFreightOrderHasReference } if _, err := tx.ExecContext( ctx, `DELETE FROM procurement_requests WHERE freight_order_item_id IN ( SELECT id FROM freight_order_items WHERE freight_order_id = ? ) AND reference_asset_id IS NULL AND purchase_task_id IS NULL AND status IN ('BLOCKED', 'NEEDS_IMAGE', 'SOURCE_CHANGED')`, storedOrderID, ); err != nil { return nil, repositoryFailure(err) } var remainingRequests int err = tx.QueryRowContext( ctx, `SELECT EXISTS ( SELECT 1 FROM freight_order_items AS item JOIN procurement_requests AS request ON request.freight_order_item_id = item.id WHERE item.freight_order_id = ? )`, storedOrderID, ).Scan(&remainingRequests) if err != nil { return nil, repositoryFailure(err) } if remainingRequests != 0 { return nil, repositoryFailure(usecase.ErrRepositoryInvariant) } rows, err := tx.QueryContext( ctx, `SELECT image.storage_key FROM freight_item_images AS image JOIN freight_order_items AS item ON item.id = image.freight_order_item_id WHERE item.freight_order_id = ? AND image.status = 'READY' AND image.storage_key IS NOT NULL ORDER BY image.storage_key`, storedOrderID, ) if err != nil { return nil, repositoryFailure(err) } storageKeys := make([]string, 0) for rows.Next() { var storageKey string if err := rows.Scan(&storageKey); err != nil { rows.Close() return nil, repositoryFailure(err) } storageKeys = append(storageKeys, storageKey) } if err := rows.Err(); err != nil { rows.Close() return nil, repositoryFailure(err) } if err := rows.Close(); err != nil { return nil, repositoryFailure(err) } if _, err := tx.ExecContext( ctx, `DELETE FROM freight_order_items WHERE freight_order_id = ?`, storedOrderID, ); err != nil { return nil, repositoryFailure(err) } result, err := tx.ExecContext( ctx, `DELETE FROM freight_orders WHERE creator_subject = ? AND id = ?`, creatorSubject, storedOrderID, ) if err != nil { return nil, repositoryFailure(err) } deleted, err := result.RowsAffected() if err != nil { return nil, repositoryFailure(err) } if deleted != 1 { return nil, repositoryFailure(usecase.ErrRepositoryInvariant) } if err := tx.Commit(); err != nil { return nil, repositoryFailure(err) } return storageKeys, nil } const freightSyncSelect = `SELECT id, creator_subject, created_by_user_id, mode, order_number, created_from, created_to, watermark_through, query_sha256, status, error_code, order_count, item_count, created_at, started_at, finished_at FROM erp_sync_runs ` func scanFreightSync(scanner rowScanner) (domain.FreightSyncRun, error) { var run domain.FreightSyncRun var orderNumber, createdFrom, createdTo sql.NullString var watermarkThrough sql.NullString var errorCode sql.NullString var createdAt string var startedAt sql.NullString var finishedAt sql.NullString err := scanner.Scan( &run.ID, &run.CreatorSubject, &run.CreatedByUserID, &run.Mode, &orderNumber, &createdFrom, &createdTo, &watermarkThrough, &run.QuerySHA256, &run.Status, &errorCode, &run.OrderCount, &run.ItemCount, &createdAt, &startedAt, &finishedAt, ) if err != nil { return domain.FreightSyncRun{}, err } if errorCode.Valid { run.ErrorCode = &errorCode.String } if orderNumber.Valid { run.OrderNumber = orderNumber.String } if createdFrom.Valid { run.CreatedFrom = createdFrom.String } if createdTo.Valid { run.CreatedTo = createdTo.String } run.WatermarkThrough, err = parseNullableTimestamp(watermarkThrough) if err != nil { return domain.FreightSyncRun{}, err } run.CreatedAt, err = parseTimestamp(createdAt) if err != nil { return domain.FreightSyncRun{}, err } run.StartedAt, err = parseNullableTimestamp(startedAt) if err != nil { return domain.FreightSyncRun{}, err } run.FinishedAt, err = parseNullableTimestamp(finishedAt) return run, err } const freightOrderSelect = `SELECT freight_orders.id, freight_orders.creator_subject, freight_orders.source_system, freight_orders.external_stock_id, freight_orders.source_code, freight_orders.platform_order_no, freight_orders.shop_name, freight_orders.source_created_at, freight_orders.order_status, freight_orders.purchase_status, freight_orders.is_canceled, freight_orders.canonical_sha256, freight_orders.revision, freight_orders.first_sync_run_id, freight_orders.last_sync_run_id, freight_orders.created_at, freight_orders.updated_at, (SELECT count(*) FROM freight_order_items WHERE freight_order_id = freight_orders.id AND is_present = 1) FROM freight_orders ` func scanFreightOrder(scanner rowScanner) (domain.FreightOrder, error) { var order domain.FreightOrder var platformOrderNo, shopName, sourceCreatedAt sql.NullString var orderStatus, purchaseStatus sql.NullString var isCanceled sql.NullBool var createdAt, updatedAt string err := scanner.Scan( &order.ID, &order.CreatorSubject, &order.SourceSystem, &order.ExternalStockID, &order.SourceCode, &platformOrderNo, &shopName, &sourceCreatedAt, &orderStatus, &purchaseStatus, &isCanceled, &order.CanonicalSHA256, &order.Revision, &order.FirstSyncRunID, &order.LastSyncRunID, &createdAt, &updatedAt, &order.ItemCount, ) if err != nil { return domain.FreightOrder{}, err } order.PlatformOrderNo = optionalString(platformOrderNo) order.ShopName = optionalString(shopName) order.OrderStatus = optionalString(orderStatus) order.PurchaseStatus = optionalString(purchaseStatus) if isCanceled.Valid { order.IsCanceled = &isCanceled.Bool } if sourceCreatedAt.Valid { parsed, err := parseTimestamp(sourceCreatedAt.String) if err != nil { return domain.FreightOrder{}, err } order.SourceCreatedAt = &parsed } order.CreatedAt, err = parseTimestamp(createdAt) if err != nil { return domain.FreightOrder{}, err } order.UpdatedAt, err = parseTimestamp(updatedAt) return order, err } func scanFreightOrderItem(scanner rowScanner) (domain.FreightOrderItem, error) { var item domain.FreightOrderItem var quantity sql.NullInt64 var originalUnitPriceMinor sql.NullInt64 var thumb, purchaseStatus sql.NullString var createdAt, updatedAt string err := scanner.Scan( &item.ID, &item.FreightOrderID, &item.ExternalItemID, &item.Title, &item.ProductSpec, &item.SKU, &quantity, &thumb, &originalUnitPriceMinor, &item.OriginalCurrency, &purchaseStatus, &item.CanonicalSHA256, &item.Revision, &item.IsPresent, &item.FirstSyncRunID, &item.LastSyncRunID, &createdAt, &updatedAt, ) if err != nil { return domain.FreightOrderItem{}, err } if quantity.Valid { value := int(quantity.Int64) item.Quantity = &value } item.ProductThumbRef = optionalString(thumb) if originalUnitPriceMinor.Valid { item.OriginalUnitPriceMinor = &originalUnitPriceMinor.Int64 } item.PurchaseStatus = optionalString(purchaseStatus) item.CreatedAt, err = parseTimestamp(createdAt) if err != nil { return domain.FreightOrderItem{}, err } item.UpdatedAt, err = parseTimestamp(updatedAt) return item, err } func nullableTimestamp(value *time.Time) any { if value == nil { return nil } return formatTimestamp(*value) } func nullableFreightQuantity(value *int) any { if value == nil { return nil } return *value } func nullableFreightSyncValue(value string) any { if value == "" { return nil } return value } func optionalString(value sql.NullString) *string { if !value.Valid { return nil } return &value.String }