feat(core): add bounded key creation contract

Expose create_redis_value through the Tauri bridge, add NX-based string creation in redis-core, and surface duplicate-key handling through stable operator notices.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Senior Frontend Engineer
2026-03-31 10:14:13 +00:00
parent 8b6689c445
commit e83c518081
7 changed files with 288 additions and 8 deletions

View File

@@ -2,8 +2,9 @@ use redis_core::{
BackendBootstrap, BackendError, CommandExecutionResult, ConnectionTestResult,
RedisCommandRequest, RedisConnectionRequest, RedisKeyBrowseRequest, RedisKeyBrowseResult,
RedisKeyMetadata, RedisKeyMetadataRequest, RedisKeyTtlUpdateRequest, RedisKeyTtlUpdateResult,
RedisValueReadRequest, RedisValueRecord, RedisValueWriteRequest, browse_keys, execute_command,
inspect_key, read_value, test_connection, update_key_ttl, write_value,
RedisValueCreateRequest, RedisValueCreateResult, RedisValueReadRequest, RedisValueRecord,
RedisValueWriteRequest, browse_keys, create_value, execute_command, inspect_key, read_value,
test_connection, update_key_ttl, write_value,
};
#[tauri::command]
@@ -45,6 +46,13 @@ fn write_redis_value(request: RedisValueWriteRequest) -> Result<RedisValueRecord
write_value(request)
}
#[tauri::command]
fn create_redis_value(
request: RedisValueCreateRequest,
) -> Result<RedisValueCreateResult, BackendError> {
create_value(request)
}
#[tauri::command]
fn update_redis_key_ttl(
request: RedisKeyTtlUpdateRequest,
@@ -62,6 +70,7 @@ fn main() {
inspect_redis_key,
read_redis_value,
write_redis_value,
create_redis_value,
update_redis_key_ttl
])
.run(tauri::generate_context!())

View File

@@ -65,6 +65,28 @@ describe("operator notices", () => {
);
});
it("maps duplicate key creation into a stable neutral notice", () => {
expect(
toBackendErrorNotice(
{
code: "already_exists",
message: "Redis key creation does not overwrite an existing key.",
detail: "key `draft:key` already exists",
},
{
operation: "key_create",
connectionName: "redis-local-fixture",
databaseLabel: "db0",
keyName: "draft:key",
},
),
).toEqual(
createNeutralNotice(
"Redis refused to proceed while creating draft:key on redis-local-fixture / db0 because the key already exists. Choose a new key name or inspect the existing key before retrying. Backend detail: Redis key creation does not overwrite an existing key. (key `draft:key` already exists).",
),
);
});
it("describes command failures with command and scope context", () => {
expect(
toBackendErrorNotice(

View File

@@ -9,6 +9,7 @@ export type BackendErrorCode =
| "invalid_connection_config"
| "unsupported_tls_mode"
| "unsupported_operation"
| "already_exists"
| "connection_failed"
| "authentication_failed"
| "command_failed"
@@ -21,6 +22,12 @@ export type BackendError = {
};
export type BackendErrorContext =
| {
operation: "key_create";
connectionName: string;
databaseLabel: string;
keyName: string;
}
| {
operation: "connection_test";
connectionName: string;
@@ -96,6 +103,7 @@ export function toBackendErrorNotice(
const backendError = toBackendError(error);
const tone =
backendError.code === "invalid_connection_config" ||
backendError.code === "already_exists" ||
backendError.code === "unsupported_operation" ||
backendError.code === "unsupported_tls_mode"
? "neutral"
@@ -115,6 +123,7 @@ function normalizeBackendErrorCode(value: unknown): BackendErrorCode {
switch (value) {
case "invalid_connection_config":
case "unsupported_tls_mode":
case "already_exists":
case "unsupported_operation":
case "connection_failed":
case "authentication_failed":
@@ -134,6 +143,8 @@ function buildHeadline(error: BackendError, context: BackendErrorContext) {
return `The request for ${target} was rejected before Redis was contacted.`;
case "unsupported_tls_mode":
return `The request for ${target} requires TLS handling that this foundation build does not support yet.`;
case "already_exists":
return `Redis refused to proceed while ${target} because the key already exists.`;
case "unsupported_operation":
return `The current desktop contract does not allow ${target} yet.`;
case "connection_failed":
@@ -155,6 +166,8 @@ function buildHint(code: BackendErrorCode, context: BackendErrorContext) {
return "Check host, port, database, search pattern, and key input before retrying.";
case "unsupported_tls_mode":
return "Keep TLS disabled in this foundation build unless product scope explicitly adds transport controls.";
case "already_exists":
return "Choose a new key name or inspect the existing key before retrying.";
case "unsupported_operation":
return "Stay on the visible read-only path or wait for a backend contract change before retrying.";
case "connection_failed":
@@ -181,6 +194,8 @@ function describeContext(context: BackendErrorContext) {
switch (context.operation) {
case "connection_test":
return `testing ${context.connectionName} on ${context.databaseLabel}`;
case "key_create":
return `creating ${context.keyName} on ${context.connectionName} / ${context.databaseLabel}`;
case "key_browse":
return `loading keys from ${context.connectionName} / ${context.databaseLabel}`;
case "value_read":