create-syncular-app 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-syncular-app",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Scaffold a new Syncular app: `create-syncular-app`",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Benjamin Kniffler",
@@ -49,6 +49,6 @@
49
49
  "!dist/**/*.test.d.ts"
50
50
  ],
51
51
  "devDependencies": {
52
- "@syncular/typegen": "0.5.1"
52
+ "@syncular/typegen": "0.6.0"
53
53
  }
54
54
  }
@@ -1,6 +1,8 @@
1
1
  query listTodos(listId) {
2
- select id, list_id, title, done, position, updated_at_ms
3
- from todos
4
- where list_id = :listId
5
- order by position, id
2
+ sql {
3
+ select id, list_id, title, done, position, updated_at_ms
4
+ from todos
5
+ where @scope(todos.list_id = :listId)
6
+ order by position, id
7
+ }
6
8
  }
@@ -1,6 +1,30 @@
1
1
  // Generated by @syncular/typegen — DO NOT EDIT.
2
2
  // irVersion: 1
3
- // irHash: sha256:4c2d58e50c85edd5a15aa6d61f2195b802e90b9056fc3cea17ceddb6ea37d0e7
3
+ // irHash: sha256:14904cd41e8ae90720d152cd47a944d2f01bf8572b97e32fa71cda8909cab768
4
+
5
+ export type SyqlRuntimeErrorCode =
6
+ | 'SYQL_RUNTIME_MISSING_REQUIRED_INPUT'
7
+ | 'SYQL_RUNTIME_UNKNOWN_INPUT'
8
+ | 'SYQL_RUNTIME_INVALID_INPUT'
9
+ | 'SYQL_RUNTIME_INVALID_GROUP'
10
+ | 'SYQL_RUNTIME_INVALID_SORT'
11
+ | 'SYQL_RUNTIME_INVALID_PAGE';
12
+
13
+ export class SyqlInputError extends Error {
14
+ readonly name = 'SyqlInputError';
15
+ constructor(readonly code: SyqlRuntimeErrorCode, message: string) {
16
+ super(message);
17
+ }
18
+ }
19
+
20
+ export interface SyqlPresent<T> {
21
+ readonly present: true;
22
+ readonly value: T;
23
+ }
24
+
25
+ export function syqlPresent<T>(value: T): SyqlPresent<T> {
26
+ return { present: true, value };
27
+ }
4
28
 
5
29
  /** A bindable SQL param/row value (the wrapper's SqlValue subset). */
6
30
  export type QueryValue =
@@ -25,8 +49,7 @@ export interface QueryClient {
25
49
  * `bind(params)` → positional args. Consumed by
26
50
  * `@syncular/react`'s `useQuery`. `Row` is the projection row
27
51
  * type; `Params` is `undefined` for a param-less query. `sqlFor`
28
- * (present only with an orderBy knob) composes the statement from a
29
- * generate-time-checked column allowlist. */
52
+ * selects a checked revision-1 SYQL physical statement when needed. */
30
53
  export interface NamedQuery<Row, Params = undefined> {
31
54
  readonly id: string;
32
55
  readonly hasParams: boolean;
@@ -66,34 +89,55 @@ export interface ListTodosRow {
66
89
  updatedAtMs: number;
67
90
  }
68
91
 
69
- /** Named parameters for 'listTodos'. */
92
+ /** Public revision-1 SYQL inputs for 'listTodos'. */
70
93
  export interface ListTodosParams {
71
94
  listId: string;
72
95
  }
73
96
 
97
+ function listTodosValidate(raw?: ListTodosParams): ListTodosParams {
98
+ const params = raw ?? ({} as ListTodosParams);
99
+ const allowed = new Set(['listId']);
100
+ for (const key of Object.keys(params)) {
101
+ if (!allowed.has(key)) throw new SyqlInputError('SYQL_RUNTIME_UNKNOWN_INPUT', 'listTodos' + ': unknown input ' + key);
102
+ }
103
+ if (!Object.prototype.hasOwnProperty.call(params, 'listId')) throw new SyqlInputError('SYQL_RUNTIME_MISSING_REQUIRED_INPUT', 'listTodos: missing required input listId');
104
+ if (!(typeof params.listId === 'string')) throw new SyqlInputError('SYQL_RUNTIME_INVALID_INPUT', 'listTodos: invalid input listId');
105
+ return params;
106
+ }
107
+
74
108
  /** Tables 'listTodos' reads (compatibility/export surface). */
75
109
  export const listTodosTables = ['todos'] as const;
76
110
 
77
- const listTodosSql = 'select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos where list_id = ? order by position, id';
111
+ const listTodosStatements: { sql: string; bind: (params: ListTodosParams) => QueryValue[] }[] = [
112
+ { sql: 'select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos where (todos.list_id = ?) order by position, id', bind: (params) => [params.listId] },
113
+ ];
114
+ function listTodosSelect(raw: ListTodosParams): { sql: string; bind: QueryValue[] } {
115
+ const params = listTodosValidate(raw);
116
+ let mask = 0;
117
+ const statement = listTodosStatements[mask * 1 + 0];
118
+ if (statement === undefined) throw new Error('invalid generated SYQL statement index');
119
+ return { sql: statement.sql, bind: statement.bind(params) };
120
+ }
78
121
 
79
122
  /** Run the 'listTodos' named query (SELECT-only). */
80
123
  export async function listTodos(client: QueryClient, params: ListTodosParams): Promise<ListTodosRow[]> {
81
- const rows = await client.query(listTodosSql, [params.listId]);
124
+ const selected = listTodosSelect(params);
125
+ const rows = await client.query(selected.sql, selected.bind);
82
126
  return rows as unknown as ListTodosRow[];
83
127
  }
84
128
 
85
129
  /** Revisioned reactive descriptor for `useQuery(listTodosQuery, params)`. */
86
130
  export const listTodosQuery: NamedQuery<ListTodosRow, ListTodosParams> = {
87
- id: 'sha256:4c2d58e50c85edd5a15aa6d61f2195b802e90b9056fc3cea17ceddb6ea37d0e7/listTodos',
131
+ id: 'sha256:14904cd41e8ae90720d152cd47a944d2f01bf8572b97e32fa71cda8909cab768/listTodos',
88
132
  hasParams: true,
89
- sql: listTodosSql,
133
+ sql: 'select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos where (todos.list_id = ?) order by position, id',
134
+ sqlFor: (params: ListTodosParams) => listTodosSelect(params).sql,
90
135
  tables: listTodosTables,
91
136
  dependencies: (params) => [
92
137
  { table: 'todos', scopeKeys: ['list:' + String(params.listId) + ''] },
93
138
  ],
94
- coverage: (params) => [
95
- { base: { table: 'todos', variable: 'list_id' }, units: [String(params.listId)] },
139
+ coverage: () => [
96
140
  ],
97
- bind: (params: ListTodosParams) => [params.listId],
141
+ bind: (params: ListTodosParams) => listTodosSelect(params).bind,
98
142
  rowKey: (row) => [row.id],
99
143
  };
@@ -1,12 +1,12 @@
1
1
  {
2
- "queryIrVersion": 2,
2
+ "queryIrVersion": 3,
3
3
  "queries": [
4
4
  {
5
5
  "name": "listTodos",
6
- "file": "list-todos.syql (query listTodos)",
7
- "sourceSql": "select id, list_id, title, done, position, updated_at_ms\n from todos\n where list_id = :listId\n order by position, id",
8
- "sql": "select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos where list_id = :listId order by position, id",
9
- "positionalSql": "select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos where list_id = ? order by position, id",
6
+ "file": "list-todos.syql",
7
+ "sourceSql": "select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos\n where (todos.list_id = :listId)\n order by position, id",
8
+ "sql": "select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos\n where (todos.list_id = :listId)\n order by position, id",
9
+ "positionalSql": "select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos where (todos.list_id = ?) order by position, id",
10
10
  "params": [
11
11
  {
12
12
  "name": "listId",
@@ -100,17 +100,44 @@
100
100
  ]
101
101
  }
102
102
  ],
103
- "coverage": [
103
+ "coverage": [],
104
+ "rowKey": [
105
+ "id"
106
+ ]
107
+ },
108
+ "syql": {
109
+ "revision": 1,
110
+ "inputs": [
104
111
  {
105
- "table": "todos",
106
- "variable": "list_id",
107
- "units": [
108
- "listId"
109
- ],
110
- "fixedScopes": []
112
+ "kind": "value",
113
+ "name": "listId",
114
+ "langName": "listId",
115
+ "type": "string",
116
+ "nullable": false,
117
+ "required": true
111
118
  }
112
119
  ],
113
- "rowKey": [
120
+ "plan": {
121
+ "backend": "variants",
122
+ "activationControls": [],
123
+ "conditions": [],
124
+ "statements": [
125
+ {
126
+ "activationMask": 0,
127
+ "sql": "select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos\n where (todos.list_id = :listId)\n order by position, id",
128
+ "positionalSql": "select id, list_id AS listId, title, done, position, updated_at_ms AS updatedAtMs from todos where (todos.list_id = ?) order by position, id",
129
+ "binds": [
130
+ {
131
+ "kind": "value",
132
+ "name": "listId",
133
+ "type": "string",
134
+ "input": "listId"
135
+ }
136
+ ]
137
+ }
138
+ ]
139
+ },
140
+ "identity": [
114
141
  "id"
115
142
  ]
116
143
  }