/** * Schema 边缘场景测试 */ import { createSchema, validateRow, getPrimaryKey, checkFieldType, astColumnToColumnDef } from '../../src/table/schema'; describe('Schema 边缘场景', () => { // ---- createSchema ---- describe('createSchema', () => { it('空列表抛出错误', () => { expect(() => createSchema('empty', {})).toThrow('at least one column'); }); it('多主键定义(取第一个标记的)', () => { const schema = createSchema('multi', { id1: { type: 'string', primaryKey: true }, id2: { type: 'string' }, }); expect(getPrimaryKey(schema)).toBe('id1'); }); it('大表定义', () => { const cols: Record = {}; for (let i = 0; i < 50; i++) { cols[`col${i}`] = { type: 'string' }; } cols.id = { type: 'string', primaryKey: true }; const schema = createSchema('big', cols); expect(Object.keys(schema.columns)).toHaveLength(51); }); }); // ---- getPrimaryKey ---- describe('getPrimaryKey', () => { it('没有标记主键时返回第一列', () => { const schema = createSchema('test', { uuid: { type: 'string', primaryKey: true }, name: { type: 'string' }, }); // 重新构造不带主键标记的 schema const noPkSchema = { name: 'test', columns: { first: { type: 'string' as const }, second: { type: 'string' as const }, }}; expect(getPrimaryKey(noPkSchema)).toBe('first'); }); }); // ---- validateRow ---- describe('validateRow', () => { const schema = createSchema('users', { id: { type: 'string', primaryKey: true }, name: { type: 'string', required: true }, bio: { type: 'string', maxLength: 200 }, score: { type: 'number', min: 0, max: 100, default: 50 }, active: { type: 'boolean', default: true }, birthday: { type: 'date' }, tags: { type: 'json', default: [] }, }); it('跳过 undefined 字段(使用默认值)', () => { const row = validateRow(schema, { id: '1', name: 'Alice' }); expect(row.id).toBe('1'); expect(row.name).toBe('Alice'); expect(row.score).toBe(50); expect(row.active).toBe(true); expect(row.tags).toEqual([]); }); it('null 值被视为不满足必填', () => { expect(() => validateRow(schema, { id: '1', name: null })).toThrow('required'); }); it('json 类型接受对象', () => { const row = validateRow(schema, { id: '1', name: 'Alice', tags: { key: 'value' } }); expect(row.tags).toEqual({ key: 'value' }); }); it('json 类型接受数组', () => { const row = validateRow(schema, { id: '1', name: 'Alice', tags: [1, 2, 3] }); expect(row.tags).toEqual([1, 2, 3]); }); it('date 类型接受有效日期字符串', () => { const row = validateRow(schema, { id: '1', name: 'Alice', birthday: '2024-01-15' }); expect(row.birthday).toBe('2024-01-15'); }); it('date 类型拒绝无效格式', () => { expect(() => validateRow(schema, { id: '1', name: 'Alice', birthday: 'not-a-date' })) .toThrow('expects valid date'); expect(() => validateRow(schema, { id: '1', name: 'Alice', birthday: 123 })) .toThrow('expects valid date'); }); it('boolean 类型', () => { const row = validateRow(schema, { id: '1', name: 'Alice', active: false }); expect(row.active).toBe(false); }); it('boolean 拒绝非布尔值', () => { expect(() => validateRow(schema, { id: '1', name: 'Alice', active: 'yes' })) .toThrow('expects boolean'); }); it('number 拒绝字符串', () => { expect(() => validateRow(schema, { id: '1', name: 'Alice', score: 'high' })) .toThrow('expects number'); }); it('string 拒绝数字', () => { expect(() => validateRow(schema, { id: 123, name: 'Alice' })) .toThrow('expects string'); }); }); // ---- checkFieldType ---- describe('checkFieldType', () => { it('string 类型通过', () => { expect(() => checkFieldType('t', 'c', 'string', 'hello')).not.toThrow(); }); it('string 类型拒绝', () => { expect(() => checkFieldType('t', 'c', 'string', 123)).toThrow('expects string'); }); it('number 类型通过', () => { expect(() => checkFieldType('t', 'c', 'number', 42)).not.toThrow(); expect(() => checkFieldType('t', 'c', 'number', 3.14)).not.toThrow(); expect(() => checkFieldType('t', 'c', 'number', 0)).not.toThrow(); }); it('boolean 类型通过', () => { expect(() => checkFieldType('t', 'c', 'boolean', true)).not.toThrow(); expect(() => checkFieldType('t', 'c', 'boolean', false)).not.toThrow(); }); it('json 拒绝非对象', () => { expect(() => checkFieldType('t', 'c', 'json', 'not-object')).toThrow('expects object'); expect(() => checkFieldType('t', 'c', 'json', 123)).toThrow('expects object'); }); }); // ---- astColumnToColumnDef ---- describe('astColumnToColumnDef', () => { it('转换基础列', () => { const result = astColumnToColumnDef({ name: 'id', type: 'string' }); expect(result.type).toBe('string'); }); it('转换带修饰符的列', () => { const result = astColumnToColumnDef({ name: 'id', type: 'string', primaryKey: true, unique: true, required: true, }); expect(result.primaryKey).toBe(true); expect(result.unique).toBe(true); expect(result.required).toBe(true); }); }); });