Skip to content

Add unique constraint on tapGestures(side, tapType) and use onConflictDoUpdate #109

@ng

Description

@ng

Summary

The setGesture procedure in settings.ts manually checks for existing gestures with a SELECT query before deciding to INSERT or UPDATE. This could be replaced with a database-level unique constraint and onConflictDoUpdate, which is both simpler and race-condition-safe.

Current Behavior (settings.ts:198-250)

// Check if gesture already exists
const existing = await db.select().from(tapGestures)
  .where(and(
    eq(tapGestures.side, input.side),
    eq(tapGestures.tapType, input.tapType)
  )).limit(1)

if (existing.length > 0) {
  // Update existing
} else {
  // Create new
}

Proposed Change

  1. Migration: Add unique constraint on tapGestures(side, tapType)
  2. Code: Replace the SELECT+branch with a single onConflictDoUpdate:
const [result] = await db
  .insert(tapGestures)
  .values(input)
  .onConflictDoUpdate({
    target: [tapGestures.side, tapGestures.tapType],
    set: { ...input, updatedAt: new Date() },
  })
  .returning()

Benefits

  • Eliminates race condition (two concurrent requests could both see no existing record)
  • Simpler code (one query instead of two)
  • Database enforces the uniqueness invariant
  • Consistent with the pattern used in device.ts for deviceState

Notes

  • Requires a Drizzle migration to add the unique constraint
  • Existing data should be checked for duplicates before migration
  • Non-blocking improvement — current code works correctly under normal conditions

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions