apaas-object-skill

Use when creating, updating, or deleting aPaaS data objects (schemas/tables), managing field definitions, or troubleshooting schema API errors like type mismatches, missing fields, or dependency ordering issues.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "apaas-object-skill" with this command: npx skills add ennann/apaas-object-skill/ennann-apaas-object-skill-apaas-object-skill

aPaaS 数据对象管理

管理 aPaaS 平台数据对象(表)的创建、更新、删除。通过 Node SDK 的 client.schema.* 接口操作。

快速导航

必读陷阱 | 前置条件 | 核心 API | 创建对象(两步走) | 字段类型映射 | 字段 settings 模板 | SQL 转换 | 多对象分阶段创建 | 错误处理 | 完整示例

必读陷阱清单

先看完这 5 条再动手,每条都是真实踩坑总结。

  1. schema.create 静默忽略 fields — 传了字段定义也返回成功,但字段不会被创建。必须两步走:先 create 空壳,再 update 添加字段。
  2. text/multilingualmultiline = 整批静默失败 — API 返回 code: "0" + data: null,看似成功但所有字段都没创建。始终用完整 settings 模板。
  3. metadata type ≠ schema typenumber 要写 floatoption 要写 enumfile 要写 attachment。用错直接报类型不识别。
  4. 系统字段 _id/_createdBy 等不能手动创建 — 新建对象自动生成 5 个系统字段,重复定义会冲突报错。
  5. 批量上限 10 个对象schema.create/update/delete 每次最多 10 个,超过需分批。

前置条件

使用此 skill 前,必须确保以下环境已就绪:

  1. 安装 Node.js(>= 16)
  2. 安装 SDKnpm install apaas-oapi-client@^0.1.37schema 模块从 0.1.37 开始提供,低版本会报 Cannot read properties of undefined
  3. 获取凭据(在 aPaaS 平台的应用管理中获取):
    • Client ID(格式:c_ 开头,如 c_a4dd955086ec45a882b9
    • Client Secret(格式:32 位十六进制,如 a62fc785b97a4847810a4f319ccbdb5e
    • Namespace(必须以 __c 结尾,如 package_5dc5b7__c

初始化 Client

SDK 导出结构为 { apaas: { Client } }不是直接导出 Client

// ESM
import { apaas } from 'apaas-oapi-client';

// CommonJS
const { apaas } = require('apaas-oapi-client');

构造参数为顶层平铺,不要嵌套在 auth 或其他对象下:

// ✅ 正确
const client = new apaas.Client({
    clientId: 'c_a4dd955086ec45a882b9',
    clientSecret: 'a62fc785b97a4847810a4f319ccbdb5e',
    namespace: 'package_5dc5b7__c'
});
await client.init();

// ❌ 错误:不能解构 Client 直接用
const { Client } = require('apaas-oapi-client');  // Client is undefined

// ❌ 错误:不能嵌套在 auth 下
new apaas.Client({ auth: { clientId: '...' } });  // 鉴权失败

系统预置规则

系统预置对象(只读)

平台预置两张数据表,不可修改、不可删除

对象说明
_user用户表
_department部门表

系统字段识别规则

API name 以 _ 下划线开头的对象或字段,均为系统预置,只读不可修改/删除。

默认字段

任何新建的空白对象,系统自动生成以下 5 个字段,无需手动创建:

字段类型说明
_idbigint记录唯一标识
_createdBylookup创建人
_createdAtdatetime创建时间
_updatedBylookup最后修改人
_updatedAtdatetime最后修改时间

注意

  • 不要在 schema.create 的 fields 中定义这些字段,会冲突报错
  • 不要尝试用 schema.update 修改或删除这些字段
  • _user_department 可以作为 lookup 的 referenced_object_api_name 目标(如关联用户/部门)

核心 API

接口用途
client.schema.create({ objects })批量创建数据对象
client.schema.update({ objects })批量更新对象(添加/修改/删除字段)
client.schema.delete({ api_names })批量删除数据对象

批量上限schema.create / update / delete 每次调用最多 10 个对象,超过时需分批调用:

// 通用分批执行:将 items 按 batchSize 拆分,逐批调用 fn
async function batchExecute<T>(items: T[], batchSize: number, fn: (batch: T[]) => Promise<any>) {
    for (let i = 0; i < items.length; i += batchSize) {
        const batch = items.slice(i, i + batchSize);
        const result = await fn(batch);
        // 检查 result(见"响应验证"章节)
    }
}

// 示例:创建 25 个空壳对象
const allObjects = [/* ... 25 个对象定义 ... */];
await batchExecute(allObjects, 10, (batch) => client.schema.create({ objects: batch }));

| client.object.listWithIterator() | 列出所有数据对象 | | client.object.metadata.fields({ object_name }) | 获取对象所有字段元数据 | | client.object.metadata.export2markdown() | 导出对象元数据为 Markdown |

创建对象(两步走,必须遵守)

schema.create 会静默忽略 fields 参数 — 即使传了字段定义,返回 code: 0,但实际只创建空壳对象,字段不会被创建。

必须采用两步走:先 create 空壳,再 update 添加字段。

// 步骤 1:创建空壳对象(不传 fields,或传了也会被忽略)
await client.schema.create({
    objects: [{
        api_name: 'product',
        label: { zh_cn: '产品', en_us: 'Product' },
        settings: { display_name: '_id', allow_search_fields: ['_id'], search_layout: [] }
    }]
});

// 步骤 2:用 update + operator:'add' 添加字段
await client.schema.update({
    objects: [{
        api_name: 'product',
        fields: [
            { operator: 'add', api_name: 'name',
              label: { zh_cn: '产品名称', en_us: 'Name' },
              type: { name: 'text', settings: { required: true, unique: false, case_sensitive: false, multiline: false, max_length: 200 } },
              encrypt_type: 'none' }
        ]
    }]
});

字段就位后可再次调用 schema.updatedisplay_name_id 更新为实际字段(如 name),注意 不能用 _name。多对象场景见「三阶段创建法」。

更新对象

三种操作通过 operator 字段区分:

await client.schema.update({
    objects: [{
        api_name: 'product',
        fields: [
            // 添加字段
            { operator: 'add', api_name: 'desc', label: { zh_cn: '描述', en_us: 'Desc' },
              type: { name: 'text', settings: { required: false, unique: false, case_sensitive: false, multiline: true, max_length: 1000 } }, encrypt_type: 'none' },
            // 修改字段(必须带完整 type,只改 label 会报错)
            { operator: 'replace', api_name: 'code',
              label: { zh_cn: '编号', en_us: 'Code' },
              type: { name: 'text', settings: { required: true, unique: true, case_sensitive: false, multiline: false, max_length: 100 } } },
            // 删除字段(只需 api_name)
            { operator: 'remove', api_name: 'desc' }
        ]
    }]
});

删除对象

await client.schema.delete({ api_names: ['product', 'order'] });

字段类型映射(关键陷阱)

metadata 返回的类型名和 schema 接口接受的类型名不一致,以下类型必须转换(用错会报类型不识别):

Metadata TypeSchema Type
numberfloat
optionenum
fileattachment
autoIdauto_number
mobileNumberphone
avatarOrLogoavatar
referenceFieldreference_field

其余类型同名直接使用:textbigintdatedatetimebooleanlookuprichTextemailregiondecimalmultilingual

完整映射见 references/field-schema-rules.tsSCHEMA_TYPE_BY_METADATA_TYPE

各字段类型 settings 模板(必须遵守)

致命陷阱:某些 settings 字段看似可选实则必填。缺失时 API 返回 code: "0" + data: null,看似成功但字段不会被创建。更危险的是,同一批次中一个字段缺少必填 settings,会导致整批所有字段都静默失败

下表中用 ⚠️ 标记的 settings 为必填项,不传会导致静默失败。始终使用下方完整模板,不要省略任何字段。

Schema Type完整 settings 模板
text{ required: false, unique: false, case_sensitive: false, ⚠️ multiline: false, max_length: 255 }
float{ required: false, unique: false, display_as_percentage: false, decimal_places_number: 2 }
bigint{ required: false, unique: false }
date / datetime{ required: false }
enum{ required: false, multiple: false, option_type: "custom", options: [{label, api_name, color, active}] }
boolean{ default_value: true, description_if_true: {zh_cn, en_us}, description_if_false: {zh_cn, en_us} }
lookup{ required: false, multiple: false, referenced_object_api_name: "target" }
reference_field{ current_lookup_field_api_name: "...", target_reference_field_api_name: "..." }
attachment{ required: false, any_type: true, max_uploaded_num: 10, mime_types: [] }
auto_number{ ⚠️ generation_method: "random", digits: 1, prefix: "", suffix: "", start_at: "1" }
richText{ required: false, max_length: 1000 }
phone{ required: false, unique: false }
avatar{ display_style: "square" }
email{ required: false, unique: false }
region{ required: false, multiple: false, has_level_strict: true, strict_level: 4 }
decimal{ required: false, unique: false, display_as_percentage: false, decimal_places: 2 }
multilingual{ required: false, unique: false, case_sensitive: false, ⚠️ multiline: false, max_length: 1000 }

已确认的必填 settings(缺失 = 静默失败):

  • text / multilingualmultiline 必须显式传 truefalse
  • auto_numbergeneration_method 必须传(如 "random"

enum 选项颜色blue, cyan, green, yellow, orange, red, magenta, purple, blueMagenta, grey

从关系型数据库设计转换为 aPaaS 对象

用户提供的数据模型文档可能基于 MySQL、PostgreSQL、SQLite 等关系型数据库设计。以下规则指导如何将其转换为 aPaaS 平台的对象和字段。

转换完成后,必须先生成转换确认表呈现给用户确认,再执行创建操作。

SQL 列类型 → aPaaS 字段类型

SQL 类型aPaaS Schema Typesettings 要点转换说明
VARCHAR(n) / CHAR(n)textmultiline: false, max_length: nn > 255 时建议确认是否需要多行
TEXT / LONGTEXT / MEDIUMTEXTtextmultiline: true, max_length: 100000大文本映射为多行文本
INT / INTEGER / BIGINT / SERIALbigintrequired: false, unique: falseaPaaS 无 int/bigint 区分,统一用 bigint
FLOAT / DOUBLE / REALfloatdecimal_places_number: 2按需调整小数位
DECIMAL(p,s) / NUMERIC(p,s)decimaldecimal_places: ss 映射为 decimal_places
DATEdaterequired: false直接映射
DATETIME / TIMESTAMPdatetimerequired: false统一映射为 datetime
BOOLEAN / TINYINT(1) / BITbooleandefault_value: true/false注意转换 DEFAULT 值
ENUM('a','b','c')enum每个枚举值转为 options 数组项见下方枚举转换规则
JSON(存富文本)richTextmax_length: 1000仅当 JSON 用于富文本时
BLOB / BINARY / VARBINARYattachmentany_type: true二进制文件类的列

特殊语义识别(根据列名或注释推断更精确的类型):

列名模式推断 aPaaS 类型判断依据
email / *_email / mailemail列名含 email/mail
phone / mobile / tel / *_phonephone列名含 phone/mobile/tel
avatar / logo / profile_imageavatar列名含 avatar/logo
auto_number / serial_no / *_code(自增编号类)auto_number列名暗示自增编号且有 AUTO_INCREMENT 或 SERIAL
region / province / city / addressregion列名含地区信息

注意:语义识别是启发式的,转换后必须让用户确认。当无法确定时,默认映射为 text

SQL 约束 → aPaaS 字段 settings

SQL 约束aPaaS settings说明
NOT NULLrequired: true非空约束
UNIQUEunique: true唯一约束
DEFAULT valuedefault_value: value(boolean)仅 boolean 类型支持默认值
PRIMARY KEY (id)不转换aPaaS 自动生成 _id,忽略用户的主键列
AUTO_INCREMENT通常忽略_id 自动处理;如果是业务编号列,用 auto_number
CHECK不直接支持需要在应用层实现或告知用户 aPaaS 不支持
INDEX不转换aPaaS 自动管理索引

外键与关联关系 → lookup / reference_field

这是转换中最关键的部分。关系型数据库用外键表达关联,aPaaS 用 lookup 和 reference_field。

关系型设计aPaaS 转换示例
外键列order.customer_id REFERENCES customer(id)在 order 上创建 lookup 字段,referenced_object_api_name: 'customer'customer_id INT FK → lookup
一对多(一个 customer 有多个 order)多的一方(order)加 lookupmultiple: false)指向一的一方标准 lookup
多对多(中间表 student_course(student_id, course_id)消除中间表,在任一方加 lookupmultiple: true)指向另一方中间表不创建为 aPaaS 对象
自关联employee.manager_id REFERENCES employee(id)同一对象上创建 lookup 指向自身referenced_object_api_name 指向自己
外键 + 需要显示关联对象的字段(如订单列表要显示客户名称)先建 lookup,再建 reference_field 引用目标对象的字段lookup + reference_field 组合

中间表识别规则

  • 表只有两个外键列(+ 可能的 id 和时间戳)
  • 表名是两个实体名的组合(如 student_courseuser_roletag_article
  • 没有独立的业务字段

遇到中间表时:

  1. 不要创建为 aPaaS 对象
  2. 在关系的某一方创建 lookupmultiple: true)指向另一方
  3. 选择哪一方加 lookup 时,优先选择业务上"主动关联"的一方(如学生选课 → 在 student 上加 lookup 指向 course)
  4. 如果中间表有额外业务字段(如 scoreenrolled_at),则必须保留为独立对象,两端各用一个 lookup

SQL ENUM → aPaaS enum 转换规则

-- SQL 定义
status ENUM('draft', 'published', 'archived') NOT NULL DEFAULT 'draft'

转换为:

{
    operator: 'add',
    api_name: 'status',
    label: { zh_cn: '状态', en_us: 'Status' },
    type: {
        name: 'enum',
        settings: {
            required: true,    // 来自 NOT NULL
            multiple: false,
            option_source: 'custom',
            options: [
                { label: { zh_cn: '草稿', en_us: 'Draft' }, api_name: 'draft', color: 'grey', active: true },
                { label: { zh_cn: '已发布', en_us: 'Published' }, api_name: 'published', color: 'green', active: true },
                { label: { zh_cn: '已归档', en_us: 'Archived' }, api_name: 'archived', color: 'blue', active: true }
            ]
        }
    },
    encrypt_type: 'none'
}

注意

  • SQL 的 ENUM 值直接作为 api_name(需合法:小写字母、数字、下划线)
  • label 的中文需要根据语义翻译,无法机械转换,转换时用英文作为占位、中文标注"待确认"
  • 颜色按顺序从 enum 选项颜色(见 settings 模板章节)中轮询分配

转换工作流(必须遵守)

拿到用户的数据库设计文档(SQL DDL、ER 图描述、表格等)后,按以下流程执行:

第一步:解析与识别

  1. 提取所有表(→ aPaaS 对象)和列(→ aPaaS 字段)
  2. 识别主键列 → 忽略(aPaaS 用 _id
  3. 识别外键列 → 标记为 lookup 候选
  4. 识别中间表 → 标记为"消除"或"保留"
  5. 识别 ENUM 列 → 提取枚举值列表
  6. 对每个列按「SQL 列类型映射表」和「语义识别规则」确定 aPaaS 类型

第二步:生成转换确认表

以 Markdown 表格形式呈现给用户,必须等待用户确认后才能执行创建

## 转换结果确认

### 对象列表
| SQL 表名 | aPaaS 对象 api_name | 标签(zh_cn) | 处理方式 |
|---|---|---|---|
| customer | customer | 客户 | 创建 |
| order | order | 订单 | 创建 |
| order_item | order_item | 订单明细 | 创建 |
| customer_tag | — | — | ⚠️ 识别为中间表,不创建(在 customer 上加 tags lookup) |

### 字段转换明细
| 对象 | SQL 列 | SQL 类型 | → aPaaS 类型 | api_name | 说明 |
|---|---|---|---|---|---|
| customer | id | INT PK | — | — | 忽略(用系统 _id) |
| customer | name | VARCHAR(100) NOT NULL | text | name | required: true, max_length: 100 |
| customer | email | VARCHAR(200) | email | email | 语义识别为 email 类型 |
| customer | status | ENUM('active','inactive') | enum | status | 2 个选项 |
| order | customer_id | INT FK→customer | lookup | customer | 关联客户 |
| order | total | DECIMAL(10,2) | decimal | total | decimal_places: 2 |

### 需要确认的项
- [ ] customer.email: 推断为 `email` 类型,是否正确?还是保持 `text`?
- [ ] customer_tag 识别为中间表,是否正确?如果该表有额外业务字段请告知
- [ ] enum 选项的中文标签是否准确?

请确认或修改后,我将按照三阶段创建法执行。

第三步:用户确认后执行

用户确认后,按「多对象依赖分析与分阶段创建」章节的流程执行(1a 空壳 → 1b 基础字段 → 2 lookup → 3 reference_field)。

不可转换的 SQL 特性

以下 SQL 特性在 aPaaS 中无直接对应,需告知用户:

SQL 特性aPaaS 处理方式
存储过程 / 触发器不支持,需用应用逻辑实现
视图(VIEW)不支持,忽略
复合主键不支持,aPaaS 用 _id 单列主键
复合唯一约束(多列联合)不支持单字段级 unique 无法表达联合唯一
CHECK 约束不直接支持,需在应用层校验
分区表不支持,忽略
自定义函数 / 计算列不支持

遇到这些特性时,在转换确认表中标注"⚠️ 不支持"并给出替代建议(如果有的话)。

多对象依赖分析与分阶段创建(核心策略)

当一个应用有多张数据表且互相关联时,不能一次性创建带 lookup 的完整对象

问题:循环依赖

订单(order) --lookup--> 客户(customer)
客户(customer) --lookup--> 订单(order)   // 互相引用,谁先创建?

lookup 字段要求目标对象已存在,互相引用时直接创建必然失败。

解决:三阶段创建法

阶段 1a — 创建空壳对象:所有对象只建壳子,不传 fields(传了也会被忽略)。display_name 暂时指向 _id

// 阶段 1a:创建所有空壳
await client.schema.create({
    objects: [
        { api_name: 'customer', label: { zh_cn: '客户', en_us: 'Customer' },
          settings: { display_name: '_id' } },
        { api_name: 'order', label: { zh_cn: '订单', en_us: 'Order' },
          settings: { display_name: '_id' } }
    ]
});

阶段 1b — 添加基础字段:用 schema.update + operator: 'add' 给每个对象补上基础字段(text, bigint, decimal, enum 等不依赖其他对象的字段)。

// 阶段 1b:补基础字段
await client.schema.update({
    objects: [
        { api_name: 'customer', fields: [
            { operator: 'add', api_name: 'name', label: { zh_cn: '客户名', en_us: 'Name' },
              type: { name: 'text', settings: { required: true, unique: false, case_sensitive: false, multiline: false, max_length: 200 } }, encrypt_type: 'none' }
        ]},
        { api_name: 'order', fields: [
            { operator: 'add', api_name: 'order_no', label: { zh_cn: '订单号', en_us: 'Order No' },
              type: { name: 'text', settings: { required: true, unique: true, case_sensitive: false, multiline: false, max_length: 50 } }, encrypt_type: 'none' }
        ]}
    ]
});

阶段 2 — 补充 lookup 字段:所有对象已存在,用 schema.update + operator: 'add' 给每个对象补上 lookup 字段。

// 阶段 2:所有对象已存在,补 lookup
await client.schema.update({
    objects: [
        {
            api_name: 'order',
            fields: [
                { operator: 'add', api_name: 'customer', label: { zh_cn: '客户', en_us: 'Customer' },
                  type: { name: 'lookup', settings: { required: false, multiple: false, referenced_object_api_name: 'customer' } },
                  encrypt_type: 'none' }
            ]
        },
        {
            api_name: 'customer',
            fields: [
                { operator: 'add', api_name: 'latest_order', label: { zh_cn: '最近订单', en_us: 'Latest Order' },
                  type: { name: 'lookup', settings: { required: false, multiple: false, referenced_object_api_name: 'order' } },
                  encrypt_type: 'none' }
            ]
        }
    ]
});

阶段 3 — 补充 reference_field:lookup 就位后,添加引用字段。

// 阶段 3:lookup 就位后,补 reference_field
await client.schema.update({
    objects: [{
        api_name: 'order',
        fields: [
            { operator: 'add', api_name: 'customer_name', label: { zh_cn: '客户名称', en_us: 'Customer Name' },
              type: { name: 'reference_field', settings: {
                  current_lookup_field_api_name: 'customer',
                  target_reference_field_api_name: 'name'
              } }, encrypt_type: 'none' }
        ]
    }]
});

依赖分析流程

拿到需求后,按此流程分析:

  1. 列出所有对象和字段,标记哪些字段是 lookup / lookup_multi / reference_field
  2. 画出依赖关系:lookup 的 referenced_object_api_name 指向谁
  3. 分类到各阶段
    • 阶段 1a:schema.create 创建所有空壳对象(不传 fields)
    • 阶段 1b:schema.update 添加基础字段(text, bigint, float, date, datetime, enum, boolean, attachment, auto_number, richText, phone, avatar, email, region, decimal, multilingual)
    • 阶段 2:schema.update 添加 lookup / lookup_multi
    • 阶段 3:schema.update 添加 reference_field
  4. 始终用此流程,即使没有循环依赖也不要尝试在 create 中传 fields

删除顺序(逆向)

删除时必须反向操作:

  1. 先删 reference_field(依赖 lookup)
  2. 再删 lookup / lookup_multi(依赖目标对象)
  3. 最后删对象本身

删除所有对象(完整工作流)

清理环境或重建数据模型时,需要删除应用内所有自定义对象。流程如下:

// 步骤 1:获取所有自定义对象(_ 开头为系统预置,不可删除)
const allObjects = await client.object.listWithIterator();
const customObjects = allObjects.items.filter(o => !o.apiName.startsWith('_'));
if (customObjects.length === 0) return;

// 步骤 2:收集依赖字段
const fieldsByType: Record<string, { object: string; field: string }[]> = { referenceField: [], lookup: [] };
for (const obj of customObjects) {
    const result = await client.object.metadata.fields({ object_name: obj.apiName });
    for (const field of result.data?.fields || []) {
        if (field.apiName.startsWith('_')) continue;
        const typeName = field.type?.name || field.type;
        if (typeName === 'referenceField' || typeName === 'lookup') {
            fieldsByType[typeName].push({ object: obj.apiName, field: field.apiName });
        }
    }
}

// 步骤 3:按依赖顺序删字段(reference_field → lookup)
for (const typeName of ['referenceField', 'lookup']) {
    const items = fieldsByType[typeName];
    if (items.length === 0) continue;
    const grouped: Record<string, { operator: 'remove'; api_name: string }[]> = {};
    for (const { object, field } of items) {
        (grouped[object] ??= []).push({ operator: 'remove', api_name: field });
    }
    await client.schema.update({
        objects: Object.entries(grouped).map(([api_name, fields]) => ({ api_name, fields }))
    });
}

// 步骤 4:删除所有对象
await client.schema.delete({ api_names: customObjects.map(o => o.apiName) });

删除后建议用 verifyObjects()client.object.listWithIterator() 确认清理干净。

约束速记

  • reference_field 只能引用 multiple: false 的 lookup
  • lookup_multimultiple: true不能作为 reference_field 的引导字段
  • 同一批 schema.update 中,add 的执行顺序不保证,不要在同一批里 add lookup 又 add 依赖它的 reference_field

失败恢复与幂等重跑

多阶段创建过程中,任意阶段都可能失败。以下是各阶段失败后的状态和恢复策略:

各阶段失败后的状态

失败点已完成的状态恢复策略
阶段 1a 失败部分空壳对象可能已创建重跑 1a,已存在的对象会报 k_ec_000015(含 "exist"),安全忽略
阶段 1b 失败空壳对象存在,部分字段可能已添加重跑 1b,已存在的字段会报错,可通过先查询 metadata 跳过已有字段
阶段 2 失败基础字段已就位,部分 lookup 可能已添加同上,查询后跳过已有 lookup
阶段 3 失败lookup 已就位,部分 reference_field 可能已添加同上,查询后跳过已有 reference_field

幂等重跑模式

// 查询已有字段,跳过已存在的
async function addFieldsIdempotent(objectName: string, fieldsToAdd: any[]) {
    const existing = await client.object.metadata.fields({ object_name: objectName });
    const existingNames = new Set(
        (existing.data?.fields || []).map((f: any) => f.apiName)
    );
    const newFields = fieldsToAdd.filter(f => !existingNames.has(f.api_name));
    if (newFields.length === 0) {
        console.log(`  [SKIP] ${objectName}: 所有字段已存在`);
        return;
    }
    const result = await client.schema.update({
        objects: [{ api_name: objectName, fields: newFields }]
    });
    checkResponse(result, `addFields(${objectName})`);
}

部分成功的处理

schema.update 可能在一批 10 个对象中只有部分成功。通过 data.items[].status.code 逐项检查,只重跑失败的对象:

const result = await client.schema.update({ objects: batch });
const failed = (result.data?.items || [])
    .filter((item: any) => item.status?.code !== '0')
    .map((item: any) => item.api_name);
if (failed.length > 0) {
    console.warn(`部分失败: ${failed.join(', ')},可针对这些对象重跑`);
}

常见错误与对策

错误原因修复
update 返回 code: "0" + data: null⚠️ 静默失败:字段 settings 缺少必填项(如 text 缺 multiline,auto_number 缺 generation_method),或同一批次中某个字段有此问题导致整批失败始终使用 settings 模板中的完整字段。检查方法:成功时返回 data.items,返回 data: null 即为失败
invalid generation_method valueauto_number 字段未传 generation_method必须传 generation_method: "random"
k_ec_000015 field type is requiredreplace 时只传了 label 没传 typereplace 必须带完整 type(name + settings)
k_ec_000015 + 含 "exist"对象已存在,重复创建先查询是否存在,或安全忽略此错误
create 返回成功但字段为空schema.create 静默忽略 fields必须用两步走:先 create 空壳,再 update 添加字段
创建字段类型不识别用了 metadata type(如 number用 schema type(float
display_name 报错使用了 _name,或指向不存在的字段创建空壳时先用 _id,字段就位后再更新
lookup 创建失败目标对象不存在先创建目标对象
reference_field 创建失败引导 lookup 不存在或是 multi先创建 multiple: false 的 lookup
reference_field field not foundlookup 刚创建,系统索引延迟;或目标字段类型不支持引用(如 avatar批量迁移时对 reference_field 失败做容错(打印错误但不中断),必要时加延迟重试

响应验证

每次 API 调用后必须检查三层状态

  1. result.code !== '0' — 请求级错误(参数格式问题)
  2. result.code === '0' && result.data === null — ⚠️ 静默失败(最危险:看起来成功,但字段未创建。原因:settings 缺必填项)
  3. result.data.items[].status.code !== '0' — 单个对象级错误

上述三层检查已封装在 scripts/run.tscheckResponse(result, context) 函数中,直接调用即可。

创建后验证

创建/更新对象后,调用 scripts/run.tsverifyObjects(['product', ...]) 验证:自动检查对象是否存在、列出自定义字段及类型、导出 Markdown 供人工审查。

执行脚本与目录结构

npm install && cp scripts/.env.example scripts/.env  # 填入凭据后执行:
npx ts-node scripts/run.ts

scripts/run.ts 自动加载凭据、初始化 client,内置工具函数:checkResponse()(三层响应验证)、batchExecute()(自动分批)、verifyObjects()(字段级验证)。

apaas-object-skill/
  SKILL.md                          # 主文档(Claude 读取此文件)
  references/
    FIELD_SCHEMA_RULES.md           # 字段类型映射与规则(人读版)
    field-schema-rules.ts           # 字段类型映射与规则(机器可读版,含 SQL 转换规则)
  scripts/
    run.ts                          # 执行脚本(凭据加载、client 初始化、工具函数)
    .env.example                    # 凭据配置模板

端到端完整示例

以下示例演示从 SQL DDL 到 aPaaS 对象的完整流程:

-- 输入:用户提供的 SQL 设计
CREATE TABLE customer (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(200),
  status ENUM('active', 'inactive') DEFAULT 'active'
);

CREATE TABLE `order` (
  id INT PRIMARY KEY AUTO_INCREMENT,
  order_no VARCHAR(50) NOT NULL UNIQUE,
  customer_id INT REFERENCES customer(id),
  total DECIMAL(10,2),
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
// ===== 阶段 1a:创建空壳对象 =====
await client.schema.create({
    objects: [
        { api_name: 'customer', label: { zh_cn: '客户', en_us: 'Customer' },
          settings: { display_name: '_id', allow_search_fields: ['_id'], search_layout: [] } },
        { api_name: 'order', label: { zh_cn: '订单', en_us: 'Order' },
          settings: { display_name: '_id', allow_search_fields: ['_id'], search_layout: [] } }
    ]
});

// ===== 阶段 1b:添加基础字段 =====
await client.schema.update({
    objects: [
        { api_name: 'customer', fields: [
            { operator: 'add', api_name: 'name',
              label: { zh_cn: '客户名称', en_us: 'Name' },
              type: { name: 'text', settings: { required: true, unique: false, case_sensitive: false, multiline: false, max_length: 100 } },
              encrypt_type: 'none' },
            { operator: 'add', api_name: 'email',
              label: { zh_cn: '邮箱', en_us: 'Email' },
              type: { name: 'email', settings: { required: false, unique: false } },
              encrypt_type: 'none' },
            { operator: 'add', api_name: 'status',
              label: { zh_cn: '状态', en_us: 'Status' },
              type: { name: 'enum', settings: {
                  required: false, multiple: false, option_type: 'custom',
                  options: [
                      { label: { zh_cn: '活跃', en_us: 'Active' }, api_name: 'active', color: 'green', active: true },
                      { label: { zh_cn: '停用', en_us: 'Inactive' }, api_name: 'inactive', color: 'grey', active: true }
                  ]
              } },
              encrypt_type: 'none' }
        ]},
        { api_name: 'order', fields: [
            { operator: 'add', api_name: 'order_no',
              label: { zh_cn: '订单号', en_us: 'Order No' },
              type: { name: 'text', settings: { required: true, unique: true, case_sensitive: false, multiline: false, max_length: 50 } },
              encrypt_type: 'none' },
            { operator: 'add', api_name: 'total',
              label: { zh_cn: '合计', en_us: 'Total' },
              type: { name: 'decimal', settings: { required: false, unique: false, display_as_percentage: false, decimal_places: 2 } },
              encrypt_type: 'none' }
            // created_at → 忽略,系统自动生成 _createdAt
        ]}
    ]
});

// ===== 阶段 2:添加 lookup =====
await client.schema.update({
    objects: [
        { api_name: 'order', fields: [
            { operator: 'add', api_name: 'customer',
              label: { zh_cn: '客户', en_us: 'Customer' },
              type: { name: 'lookup', settings: { required: false, multiple: false, referenced_object_api_name: 'customer' } },
              encrypt_type: 'none' }
        ]}
    ]
});

// ===== 阶段 3 (可选):添加 reference_field =====
await client.schema.update({
    objects: [
        { api_name: 'order', fields: [
            { operator: 'add', api_name: 'customer_name',
              label: { zh_cn: '客户名称', en_us: 'Customer Name' },
              type: { name: 'reference_field', settings: {
                  current_lookup_field_api_name: 'customer',
                  target_reference_field_api_name: 'name'
              } },
              encrypt_type: 'none' }
        ]}
    ]
});

// ===== 更新 display_name =====
await client.schema.update({
    objects: [
        { api_name: 'customer', settings: { display_name: 'name' } },
        { api_name: 'order', settings: { display_name: 'order_no' } }
    ]
});

// ===== 验证 =====
await verifyObjects(['customer', 'order']);

转换要点

  • id INT PRIMARY KEY → 忽略,aPaaS 用 _id
  • created_at DATETIME → 忽略,aPaaS 用 _createdAt
  • customer_id INT FK → lookup 字段
  • VARCHAR(200) 列名含 email → 语义识别为 email 类型

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

mcdonalds-coupons

No summary provided by upstream source.

Repository SourceNeeds Review
Web3

precog

Trade on prediction markets. Create a local wallet, list markets, check prices, buy and sell outcome shares. Coming soon: create and fund markets directly from this skill.

Archived SourceRecently Updated
Web3

china-sportswear-outdoor-sourcing

Comprehensive sportswear and outdoor equipment sourcing guide for international buyers – provides detailed information about China's athletic apparel, footwear, outdoor gear, and accessories manufacturing clusters, supply chain structure, regional specializations, and industry trends (2026 updated).

Archived SourceRecently Updated
Web3

china-lighting-sourcing

Comprehensive lighting industry sourcing guide for international buyers – provides detailed information about China's LED, smart, outdoor, automotive, and specialty lighting manufacturing clusters, supply chain structure, regional specializations, and industry trends (2026 updated).

Archived SourceRecently Updated