@instantdb/core
Version:
Instant's core local abstraction
209 lines (188 loc) • 5.36 kB
text/typescript
// --------
// Sanity check tests
import type {
Cursor,
Exactly,
InstantObject,
Query,
QueryResponse,
} from './queryTypes.ts';
/**
* The purpose of these sanity checks:
* If we make changes and something breaks, our build will fail.
*
* AFAIK we _could_ write this in our `tests` folder.
* The latest version of `vitest` does support `assertType`, but:
* * it's easy to get false positives if configured incorrectly
* * the api is more vebose than this
*/
export function dummyQuery<Q extends Query>(
_query: Exactly<Query, Q>,
): QueryResponse<Q, unknown> {
return 1 as any;
}
export interface ExUser {
name: string;
}
export interface ExPost {
title: string;
}
interface ExSchema {
users: ExUser;
posts: ExPost;
}
export function dummySchemaQuery<Q extends Query>(
_query: Exactly<Query, Q>,
): QueryResponse<Q, ExSchema> {
return 1 as any;
}
const sanityCheckQueries = () => {
// -----------
// Basic good inputs succeed
const r = dummyQuery({ users: {} });
// -----------
// Basic bad inputs fails
// @ts-expect-error
const r2 = dummyQuery({ users: 1 });
// @ts-expect-error
const r3 = dummyQuery({ users: '' });
// ----------------------
// Good $ clauses succeed
const r4 = dummyQuery({ users: { $: { where: { foo: 1 } } } });
const r5 = dummyQuery({ users: { $: { where: { foo: 'str' } } } });
const r6 = dummyQuery({ users: { $: { where: { foo: true } } } });
const r7 = dummyQuery({ users: { $: { where: { 'foo.bar.baz': 1 } } } });
const s1 = dummyQuery({
users: { $: { where: { foo: { in: [1, 2, 3] } } } },
});
const s1_5 = dummyQuery({
users: { $: { where: { foo: { $in: [1, 2, 3] } } } },
});
const t1 = dummyQuery({
users: { $: { where: { or: [{ foo: 1 }] } } },
});
// You can have a field named or
const t2 = dummyQuery({
users: { $: { where: { or: 'fieldNamedOr' } } },
});
const t3 = dummyQuery({
users: { $: { where: { and: [{ foo: 1 }] } } },
});
// You can have a field named and
const t4 = dummyQuery({
users: { $: { where: { and: 'fieldNamedAnd' } } },
});
const t5 = dummyQuery({
users: { $: { where: { and: [{ or: [{ foo: 1 }] }] } } },
});
// Pagination
const t6 = dummyQuery({
users: { $: { limit: 10 } },
});
const t7 = dummyQuery({
users: { $: { limit: 10, offset: 10 } },
});
const t8 = dummyQuery({
users: { $: { where: { foo: 1 }, limit: 10, offset: 10 } },
});
const cursor: Cursor = [
'61935703-bec6-4ade-ad9b-8bf382b92f69',
'995f5a9b-9ae1-4e59-97d1-df33afb44aee',
'61935703-bec6-4ade-ad9b-8bf382b92f69',
10,
];
const t9 = dummyQuery({
users: {
$: { where: { foo: 1 }, after: cursor },
},
});
const t10 = dummyQuery({
users: { $: { before: cursor } },
});
const t12 = dummyQuery({
users: { $: { where: { val: { $isNull: true } } } },
});
const t13 = dummyQuery({
users: { $: { where: { val: { $not: 'a' } } } },
});
const t14 = dummyQuery({
users: {
$: { fields: ['name', 'age', 'dob'] },
posts: { $: { fields: ['title'] } },
},
});
// ------------------
// Bad $ clauses fail
// @ts-expect-error
const r8 = dummyQuery({ users: { $: { where: 'foo' } } });
// @ts-expect-error
const r9 = dummyQuery({ users: { $: { where: { foo: {} } } } });
// @ts-expect-error
const r10 = dummyQuery({ users: { $: { where2: 1 } } });
const s2 = dummyQuery({
// @ts-expect-error
users: { $: { where: { foo: { ini: [1, 2, 3] } } } },
});
const s3 = dummyQuery({
// @ts-expect-error
users: { $: { where: { foo: [] } } },
});
const s4 = dummyQuery({
// @ts-expect-error
users: { $: { where: { val: { $isNull: 'a' } } } },
});
const s5 = dummyQuery({
// @ts-expect-error
users: { $: { where: { val: { $not: { val: 'a' } } } } },
});
// ----------------
// Good Nested queries succeed
const r11 = dummyQuery({ users: { posts: {} } });
const r12 = dummyQuery({ users: {}, posts: {} });
const r13 = dummyQuery({
users: {
$: { where: { foo: 1 } },
posts: { $: { where: { foo: 1 } } },
},
});
// ----------
// Bad nested queries fail
// @ts-expect-error
const r14 = dummyQuery({ users: { foo: 1 } });
const r15 = dummyQuery({
// @ts-expect-error
users: { $: { fields: 'name' } },
});
};
const sanityCheckSchemalessResponses = () => {
// Simple Response
const r1: { users: InstantObject[] } = dummyQuery({ users: {} });
// Nested Response
const r2: { users: ({ posts: InstantObject[] } & InstantObject)[] } =
dummyQuery({ users: { posts: {} } });
// $ are ignored
const r3: { users: ({ posts: InstantObject[] } & InstantObject)[] } =
dummyQuery({
users: {
$: { where: { foo: 1 } },
posts: {},
},
});
// @ts-expect-error
r3.$;
};
function sanityCheckSchemadResponses() {
// simple response
const r1: { users: ExUser[] } = dummySchemaQuery({ users: {} });
// nested response
const r2: { users: ({ posts: ExPost[] } & ExUser)[] } = dummySchemaQuery({
users: { posts: {} },
});
// id included, but no other keys are allowed
const r3 = dummySchemaQuery({ users: {} });
const u = r3.users[0];
const id: string = u.id;
const name: string = u.name;
// @ts-expect-error
const title: string = u.title;
}