diff --git a/client/packages/cli/__tests__/__snapshots__/updateSchemaFile.test.ts.snap b/client/packages/cli/__tests__/__snapshots__/updateSchemaFile.test.ts.snap new file mode 100644 index 0000000000..e935e58dd7 --- /dev/null +++ b/client/packages/cli/__tests__/__snapshots__/updateSchemaFile.test.ts.snap @@ -0,0 +1,248 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`adds a link when links object is empty 1`] = ` +" +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + todos: i.entity({ + title: i.string(), + }), + users: i.entity({ + email: i.string(), + }), + }, + links: { + todoOwner: { + forward: { + on: 'todos', + has: 'one', + label: 'owner', + }, + reverse: { + on: 'users', + has: 'many', + label: 'todos', + }, + }, + }, + rooms: {}, +}); + +export default _schema; +" +`; + +exports[`drops constraints removed by server 1`] = ` +" +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + todos: i.entity({ + title: i.string(), + done: i.boolean().optional(), + }), + }, + links: {}, + rooms: {}, +}); + +export default _schema; +" +`; + +exports[`handles quoted keys for entities, attrs, and links 1`] = ` +" +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + todos: i.entity({ + title: i.string(), + }), + users: i.entity({ + email: i.string(), + }), + 'user-profiles': i.entity({ + 'display-name': i.string(), + 'avatar-url': i.string(), + }), + }, + links: { + 'todo-owner': { + forward: { + on: 'todos', + has: 'one', + label: 'owner', + }, + reverse: { + on: 'users', + has: 'many', + label: 'todos', + }, + }, + }, + rooms: {}, +}); + +export default _schema; +" +`; + +exports[`inserts attrs into multi-line entities with indentation 1`] = ` +" +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + todos: i.entity({ + title: i.string(), + done: i.boolean().optional(), + priority: i.number(), + }), + }, + links: {}, + rooms: {}, +}); + +export default _schema; +" +`; + +exports[`preserves type params across chained calls 1`] = ` +" +import { i } from '@instantdb/core'; +import { Label } from './types'; + +const _schema = i.schema({ + entities: { + todos: i.entity({ + title: i.string(), + status: i.string<'todo' | 'done'>().unique().indexed(), + labels: i.json(), + metadata: i.json(), + }), + users: i.entity({ + email: i.string().unique(), + }), + }, + links: {}, + rooms: {}, +}); + +export default _schema; +" +`; + +exports[`removes a link with surrounding comments and commas 1`] = ` +" +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + todos: i.entity({ + title: i.string(), + }), + users: i.entity({ + email: i.string(), + }), + projects: i.entity({ + name: i.string(), + }), + }, + links: { + // owner link + /* project link */ + projectTodos: { + forward: { on: 'projects', has: 'many', label: 'todos' }, + reverse: { on: 'todos', has: 'one', label: 'project' }, + }, + }, + rooms: {}, +}); + +export default _schema; +" +`; + +exports[`removes the last link cleanly 1`] = ` +" +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + todos: i.entity({ + title: i.string(), + }), + users: i.entity({ + email: i.string(), + }), + }, + links: {}, + rooms: {}, +}); + +export default _schema; +" +`; + +exports[`updates link details 1`] = ` +" +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + todos: i.entity({ + title: i.string(), + }), + users: i.entity({ + email: i.string(), + }), + }, + links: { + todoOwner: { + forward: { + on: 'todos', + has: 'one', + label: 'owner', + required: true, + onDelete: 'cascade', + }, + reverse: { + on: 'users', + has: 'many', + label: 'todos', + onDelete: 'cascade', + }, + }, + }, + rooms: {}, +}); + +export default _schema; +" +`; + +exports[`updates single-line entity in place 1`] = ` +" +import { i } from '@instantdb/core'; + +const _schema = i.schema({ + entities: { + projects: i.entity({ + name: i.string(), + status: i.string(), + }), + todos: i.entity({ + title: i.string(), + }), + }, + links: {}, + rooms: {}, +}); + +export default _schema; +" +`; diff --git a/client/packages/cli/__tests__/mergeSchema.test.ts b/client/packages/cli/__tests__/mergeSchema.test.ts deleted file mode 100644 index 1f4ed8989c..0000000000 --- a/client/packages/cli/__tests__/mergeSchema.test.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { describe, test, expect } from 'vitest'; -import { mergeSchema } from '../src/util/mergeSchema'; - -test('preserves type annotations', () => { - const oldFile = ` -import { i } from '@instantdb/core'; -import { Label } from './types'; - -const _schema = i.schema({ - entities: { - $users: i.entity({ - email: i.string().unique().indexed(), - }), - todos: i.entity({ - title: i.string(), - status: i.string<'todo' | 'in_progress' | 'done'>(), - priority: i.number<1 | 2 | 3>(), - labels: i.json().optional(), - }), - projects: i.entity({ - name: i.string(), - }), - }, - links: { - todoProject: { - forward: { on: 'todos', has: 'one', label: 'project' }, - reverse: { on: 'projects', has: 'many', label: 'todos' }, - }, - projectOwner: { - forward: { on: 'projects', has: 'one', label: 'owner' }, - reverse: { on: '$users', has: 'many', label: 'projects' }, - }, - }, - rooms: { - projectRoom: { - presence: i.entity({ - cursor: i.json<{ x: number; y: number }>(), - }), - }, - }, -}); - -export default _schema; -`; - - const newFile = ` -import { i } from '@instantdb/core'; - -const _schema = i.schema({ - entities: { - $users: i.entity({ - email: i.string().unique().indexed(), - }), - todos: i.entity({ - title: i.string(), - status: i.string(), - priority: i.number(), - labels: i.json().optional(), - }), - projects: i.entity({ - name: i.string(), - }), - }, - links: { - todoProject: { - forward: { on: 'todos', has: 'one', label: 'project' }, - reverse: { on: 'projects', has: 'many', label: 'todos' }, - }, - projectOwner: { - forward: { on: 'projects', has: 'one', label: 'owner' }, - reverse: { on: '$users', has: 'many', label: 'projects' }, - }, - }, - rooms: { - projectRoom: { - presence: i.entity({ - cursor: i.json(), - }), - }, - }, -}); - -export default _schema; -`; - - const result = mergeSchema(oldFile, newFile); - - // Type annotations preserved - expect(result).toContain("i.string<'todo' | 'in_progress' | 'done'>()"); - expect(result).toContain('i.number<1 | 2 | 3>()'); - expect(result).toContain('i.json()'); - expect(result).toContain('i.json<{ x: number; y: number }>()'); - - // Import preserved - expect(result).toContain("import { Label } from './types';"); -}); - -test('preserves different import styles', () => { - const oldFile = ` -import { i } from '@instantdb/core'; -import { Label } from './types'; -import { Tag as MyTag } from './types'; -import Priority from './Priority'; -import * as Models from './models'; -import type { Meta } from './meta'; - -const _schema = i.schema({ - entities: { - a: i.entity({ f: i.json