Token导航 LogoToken导航TokenDH.com
开发需要联网github未标认证来源可访问许可证需确认审计异常

bknd-crud-updatebknd 增删改查更新

Agent Skill

bknd-crud-update 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

324

周安装

13

GitHub Stars

3

下载量

105
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:bknd-crud-update(bknd 增删改查更新)
来源仓库:https://github.com/cameronapak/bknd-skills
仓库路径:skills/bknd-crud-update
安装命令:
npx skills add https://github.com/cameronapak/bknd-skills --skill bknd-crud-update
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/cameronapak/bknd-skills --skill bknd-crud-update

简介

bknd-crud-update 用于修改现有数据库记录,适合在 Codex、Claude、Cursor、Gemini CLI 中实现用户编辑、状态变更或批量更新操作。

  • 适用场景包括个人资料修改、订单状态流转、文章内容修订及定时任务驱动的字段刷新。
  • 核心能力是通过 record ID 定位目标,并使用 PATCH/PUT 方法局部或整体更新字段值。
  • 使用方式建议先在 UI 模式验证编辑效果,再迁移至 Code 模式实现自动化流程。
  • 更新操作应遵循幂等性原则,避免并发修改引发数据不一致问题。

SKILL.md

CRUD Update

Update existing records in your Bknd database using the SDK or REST API.

Prerequisites

  • Bknd project running (local or deployed)
  • Entity exists with records to update
  • SDK configured or API endpoint known
  • Record ID or filter criteria known

When to Use UI Mode

  • Quick one-off edits
  • Manual data corrections
  • Visual verification during development

UI steps: Admin Panel > Data > Select Entity > Click record > Edit fields > Save

When to Use Code Mode

  • Application logic for user edits
  • Form submissions
  • Bulk updates
  • Automated data maintenance

Code Approach

Step 1: Set Up SDK Client

import { Api } from "bknd";

const api = new Api({
  host: "http://localhost:7654",
});

// If auth required:
api.updateToken("your-jwt-token");

Step 2: Update Single Record

Use updateOne(entity, id, data):

const { ok, data, error } = await api.data.updateOne("posts", 1, {
  title: "Updated Title",
  status: "published",
});

if (ok) {
  console.log("Updated post:", data.id);
} else {
  console.error("Failed:", error.message);
}

Step 3: Handle Response

The response object:

type UpdateResponse = {
  ok: boolean;       // Success/failure
  data?: {           // Updated record (if ok)
    id: number;
    // ...all fields with new values
  };
  error?: {          // Error info (if !ok)
    message: string;
    code: string;
  };
};

Step 4: Partial Updates

Only changed fields are required - other fields remain unchanged:

// Only update title, keep everything else
await api.data.updateOne("posts", 1, {
  title: "New Title Only",
});

// Update multiple fields
await api.data.updateOne("users", 5, {
  name: "New Name",
  bio: "Updated bio",
  updated_at: new Date().toISOString(),
});

Step 5: Update Relations

Change Linked Record (Many-to-One)

// Change post author to user ID 2
await api.data.updateOne("posts", 1, {
  author: { $set: 2 },
});

Unlink Record (Set to NULL)

// Remove author link
await api.data.updateOne("posts", 1, {
  author: { $unset: true },
});

Many-to-Many: Add Relations

// Add tags 4 and 5 to existing tags
await api.data.updateOne("posts", 1, {
  tags: { $add: [4, 5] },
});

Many-to-Many: Remove Relations

// Remove tag 2 from post
await api.data.updateOne("posts", 1, {
  tags: { $remove: [2] },
});

Many-to-Many: Replace All Relations

// Replace all tags with new set
await api.data.updateOne("posts", 1, {
  tags: { $set: [1, 3, 5] },
});

Combined Field and Relation Update

await api.data.updateOne("posts", 1, {
  title: "Updated Post",
  status: "published",
  author: { $set: newAuthorId },
  tags: { $add: [newTagId] },
});

Step 6: Update Multiple Records (Bulk)

Use updateMany(entity, where, data):

// Archive all draft posts
const { ok, data } = await api.data.updateMany(
  "posts",
  { status: { $eq: "draft" } },     // where clause (required)
  { status: "archived" },            // update values
);

// data contains affected records
console.log("Archived", data.length, "posts");

Important: where clause is required to prevent accidental update-all.

// Update posts by author
await api.data.updateMany(
  "posts",
  { author_id: { $eq: userId } },
  { author_id: newUserId },
);

// Update old records
await api.data.updateMany(
  "sessions",
  { last_active: { $lt: "2024-01-01" } },
  { expired: true },
);

REST API Approach

Update One

curl -X PATCH http://localhost:7654/api/data/posts/1 \
  -H "Content-Type: application/json" \
  -d '{"title": "Updated Title", "status": "published"}'

Update with Auth

curl -X PATCH http://localhost:7654/api/data/posts/1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{"title": "Protected Update"}'

Update Relations

# Change author
curl -X PATCH http://localhost:7654/api/data/posts/1 \
  -H "Content-Type: application/json" \
  -d '{"author": {"$set": 2}}'

# Add tags
curl -X PATCH http://localhost:7654/api/data/posts/1 \
  -H "Content-Type: application/json" \
  -d '{"tags": {"$add": [4, 5]}}'

Update Many

curl -X PATCH "http://localhost:7654/api/data/posts?where=%7B%22status%22%3A%22draft%22%7D" \
  -H "Content-Type: application/json" \
  -d '{"status": "archived"}'

React Integration

Edit Form

import { useApp } from "bknd/react";
import { useState, useEffect } from "react";

function EditPostForm({ postId }: { postId: number }) {
  const { api } = useApp();
  const [title, setTitle] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Load existing data
  useEffect(() => {
    api.data.readOne("posts", postId).then(({ data }) => {
      if (data) setTitle(data.title);
    });
  }, [postId]);

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    setLoading(true);
    setError(null);

    const { ok, error: apiError } = await api.data.updateOne("posts", postId, {
      title,
    });

    setLoading(false);

    if (!ok) {
      setError(apiError.message);
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={title}
        onChange={(e) => setTitle(e.target.value)}
        placeholder="Post title"
      />
      <button type="submit" disabled={loading}>
        {loading ? "Saving..." : "Save"}
      </button>
      {error && <p className="error">{error}</p>}
    </form>
  );
}

With SWR Revalidation

import useSWR, { mutate } from "swr";

function useUpdatePost() {
  const { api } = useApp();

  async function updatePost(id: number, updates: object) {
    const { ok, data, error } = await api.data.updateOne("posts", id, updates);

    if (ok) {
      // Revalidate the post and list
      mutate(`posts/${id}`);
      mutate("posts");
    }

    return { ok, data, error };
  }

  return { updatePost };
}

Optimistic Update

function useOptimisticUpdate() {
  const { api } = useApp();
  const [posts, setPosts] = useState<Post[]>([]);

  async function updatePost(id: number, updates: Partial<Post>) {
    // Optimistic: update immediately
    const originalPosts = [...posts];
    setPosts((prev) =>
      prev.map((p) => (p.id === id ? { ...p, ...updates } : p))
    );

    // Actual update
    const { ok } = await api.data.updateOne("posts", id, updates);

    if (!ok) {
      // Rollback on failure
      setPosts(originalPosts);
    }

    return { ok };
  }

  return { posts, updatePost };
}

Full Example

import { Api } from "bknd";

const api = new Api({ host: "http://localhost:7654" });

// Authenticate
await api.auth.login({ email: "user@example.com", password: "password" });

// Simple field update
const { ok, data } = await api.data.updateOne("posts", 1, {
  title: "Updated Title",
  updated_at: new Date().toISOString(),
});

// Update with relation changes
await api.data.updateOne("posts", 1, {
  status: "published",
  published_at: new Date().toISOString(),
  category: { $set: 3 },        // Change category
  tags: { $add: [7, 8] },       // Add new tags
});

// Bulk update: mark old drafts as archived
await api.data.updateMany(
  "posts",
  {
    status: { $eq: "draft" },
    created_at: { $lt: "2024-01-01" },
  },
  { status: "archived" }
);

// Toggle boolean field
const post = await api.data.readOne("posts", 1);
if (post.ok) {
  await api.data.updateOne("posts", 1, {
    featured: !post.data.featured,
  });
}

Common Patterns

Upsert (Update or Insert)

async function upsert(
  api: Api,
  entity: string,
  where: object,
  data: object
) {
  const { data: existing } = await api.data.readOneBy(entity, { where });

  if (existing) {
    return api.data.updateOne(entity, existing.id, data);
  }

  return api.data.createOne(entity, data);
}

// Usage
await upsert(
  api,
  "settings",
  { key: { $eq: "theme" } },
  { key: "theme", value: "dark" }
);

Conditional Update

async function updateIf(
  api: Api,
  entity: string,
  id: number,
  condition: (record: any) => boolean,
  updates: object
) {
  const { data: current } = await api.data.readOne(entity, id);

  if (!current || !condition(current)) {
    return { ok: false, error: { message: "Condition not met" } };
  }

  return api.data.updateOne(entity, id, updates);
}

// Only update if not published
await updateIf(
  api,
  "posts",
  1,
  (post) => post.status !== "published",
  { title: "New Title" }
);

Increment/Decrement Field

async function increment(
  api: Api,
  entity: string,
  id: number,
  field: string,
  amount: number = 1
) {
  const { data: current } = await api.data.readOne(entity, id);
  if (!current) return { ok: false };

  return api.data.updateOne(entity, id, {
    [field]: current[field] + amount,
  });
}

// Increment view count
await increment(api, "posts", 1, "view_count");

// Decrement stock
await increment(api, "products", 5, "stock", -1);

Soft Delete

async function softDelete(api: Api, entity: string, id: number) {
  return api.data.updateOne(entity, id, {
    deleted_at: new Date().toISOString(),
  });
}

async function restore(api: Api, entity: string, id: number) {
  return api.data.updateOne(entity, id, {
    deleted_at: null,
  });
}

Batch Update with Progress

async function batchUpdate(
  api: Api,
  entity: string,
  updates: Array<{ id: number; data: object }>,
  onProgress?: (done: number, total: number) => void
) {
  const results = [];

  for (let i = 0; i < updates.length; i++) {
    const { id, data } = updates[i];
    const result = await api.data.updateOne(entity, id, data);
    results.push(result);
    onProgress?.(i + 1, updates.length);
  }

  return results;
}

// Usage
await batchUpdate(
  api,
  "products",
  [
    { id: 1, data: { price: 19.99 } },
    { id: 2, data: { price: 29.99 } },
    { id: 3, data: { price: 39.99 } },
  ],
  (done, total) => console.log(`${done}/${total}`)
);

Common Pitfalls

Record Not Found

Problem: Update returns no data or error.

Fix: Verify record exists first:

const { data: existing } = await api.data.readOne("posts", id);
if (!existing) {
  throw new Error("Post not found");
}
await api.data.updateOne("posts", id, updates);

Invalid Relation ID

Problem: FOREIGN KEY constraint failed

Fix: Verify related record exists:

// Wrong - author ID doesn't exist
await api.data.updateOne("posts", 1, { author: { $set: 999 } });

// Correct - verify first
const { data: author } = await api.data.readOne("users", newAuthorId);
if (author) {
  await api.data.updateOne("posts", 1, { author: { $set: newAuthorId } });
}

Unique Constraint Violation

Problem: UNIQUE constraint failed when updating to existing value.

Fix: Check uniqueness before update:

// Check if email already taken by another user
const { data: existing } = await api.data.readOneBy("users", {
  where: {
    email: { $eq: newEmail },
    id: { $ne: currentUserId },  // Exclude current user
  },
});

if (existing) {
  throw new Error("Email already in use");
}

await api.data.updateOne("users", currentUserId, { email: newEmail });

Not Checking Response

Problem: Assuming success without verification.

Fix: Always check ok:

// Wrong
const { data } = await api.data.updateOne("posts", 1, updates);
console.log(data.title);  // data might be undefined!

// Correct
const { ok, data, error } = await api.data.updateOne("posts", 1, updates);
if (!ok) {
  throw new Error(error.message);
}
console.log(data.title);

Updating Without Auth

Problem: Unauthorized error.

Fix: Authenticate first:

await api.auth.login({ email, password });
// or
api.updateToken(savedToken);

await api.data.updateOne("posts", 1, updates);

Using Wrong Relation Operator

Problem: Replacing when intending to add.

Fix: Use correct operator:

// $set replaces ALL relations
await api.data.updateOne("posts", 1, { tags: { $set: [5] } });
// Post now has ONLY tag 5

// $add keeps existing and adds new
await api.data.updateOne("posts", 1, { tags: { $add: [5] } });
// Post keeps existing tags AND adds tag 5

Forgetting updateMany Where Clause

Problem: Trying to update all without where.

Fix: Always provide where clause:

// updateMany requires where clause
await api.data.updateMany(
  "posts",
  { status: { $eq: "draft" } },  // Required
  { status: "archived" }
);

// To update ALL records, use explicit condition
await api.data.updateMany(
  "posts",
  { id: { $gt: 0 } },  // Match all
  { reviewed: true }
);

Verification

After updating, verify changes:

const { ok } = await api.data.updateOne("posts", 1, { title: "New Title" });

if (ok) {
  const { data } = await api.data.readOne("posts", 1);
  console.log("Updated title:", data.title);
}

Or via admin panel: Admin Panel > Data > Select Entity > Find record > Verify fields.

DOs and DON'Ts

DO:

  • Check ok before using response data
  • Verify record exists before updating
  • Use $add/$remove for incremental relation changes
  • Handle unique constraint errors
  • Authenticate before updating protected records
  • Revalidate caches after updates

DON'T:

  • Assume updateOne always succeeds
  • Use $set for relations when meaning $add
  • Update without where clause in updateMany
  • Ignore validation errors
  • Forget to refresh UI after updates
  • Use non-existent IDs in relation operators

Related Skills

  • bknd-crud-create - Create records before updating
  • bknd-crud-read - Fetch records to get current values
  • bknd-crud-delete - Remove records instead of updating
  • bknd-define-relationship - Set up relations for linking
  • bknd-bulk-operations - Large-scale update patterns

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

33.85%
按下载量换算36

Claude

30.29%
按下载量换算32

Cursor

19.84%
按下载量换算21

Gemini CLI

9%
按下载量换算9

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

未通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills