mirror of
https://github.com/xtr-dev/rondevu-server.git
synced 2025-12-12 11:53:24 +00:00
Fix UNIQUE constraint: Use (service_name, version, username) instead of service_fqn
- Change UNIQUE constraint to composite key on separate columns - Move upsert logic into D1Storage.createService() for atomic operation - Delete existing service and its offers before inserting new one - Remove redundant delete logic from app.ts endpoint - Fixes 'UNIQUE constraint failed: services.service_fqn' error when republishing
This commit is contained in:
@@ -68,7 +68,7 @@ CREATE TABLE services (
|
|||||||
created_at INTEGER NOT NULL,
|
created_at INTEGER NOT NULL,
|
||||||
expires_at INTEGER NOT NULL,
|
expires_at INTEGER NOT NULL,
|
||||||
FOREIGN KEY (username) REFERENCES usernames(username) ON DELETE CASCADE,
|
FOREIGN KEY (username) REFERENCES usernames(username) ON DELETE CASCADE,
|
||||||
UNIQUE(service_fqn)
|
UNIQUE(service_name, version, username)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX idx_services_fqn ON services(service_fqn);
|
CREATE INDEX idx_services_fqn ON services(service_fqn);
|
||||||
|
|||||||
@@ -337,11 +337,7 @@ export function createApp(storage: Storage, config: Config) {
|
|||||||
return c.json({ error: 'Invalid signature for username' }, 403);
|
return c.json({ error: 'Invalid signature for username' }, 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete existing service if one exists (upsert behavior)
|
// Note: createService handles upsert behavior (deletes existing service if it exists)
|
||||||
const existingService = await storage.getServiceByFqn(serviceFqn);
|
|
||||||
if (existingService) {
|
|
||||||
await storage.deleteService(existingService.id, username);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate all offers
|
// Validate all offers
|
||||||
for (const offer of offers) {
|
for (const offer of offers) {
|
||||||
|
|||||||
@@ -399,7 +399,26 @@ export class D1Storage implements Storage {
|
|||||||
|
|
||||||
const { serviceName, version, username } = parsed;
|
const { serviceName, version, username } = parsed;
|
||||||
|
|
||||||
// Insert service with extracted fields
|
// Delete existing service with same (service_name, version, username) and its related offers (upsert behavior)
|
||||||
|
// First get the existing service
|
||||||
|
const existingService = await this.db.prepare(`
|
||||||
|
SELECT id FROM services
|
||||||
|
WHERE service_name = ? AND version = ? AND username = ?
|
||||||
|
`).bind(serviceName, version, username).first();
|
||||||
|
|
||||||
|
if (existingService) {
|
||||||
|
// Delete related offers first (no FK cascade from offers to services)
|
||||||
|
await this.db.prepare(`
|
||||||
|
DELETE FROM offers WHERE service_id = ?
|
||||||
|
`).bind(existingService.id).run();
|
||||||
|
|
||||||
|
// Delete the service
|
||||||
|
await this.db.prepare(`
|
||||||
|
DELETE FROM services WHERE id = ?
|
||||||
|
`).bind(existingService.id).run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert new service with extracted fields
|
||||||
await this.db.prepare(`
|
await this.db.prepare(`
|
||||||
INSERT INTO services (id, service_fqn, service_name, version, username, created_at, expires_at)
|
INSERT INTO services (id, service_fqn, service_name, version, username, created_at, expires_at)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
|||||||
Reference in New Issue
Block a user