@fadhilp/stateql 0.1.1 → 0.2.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/README.md CHANGED
@@ -8,12 +8,15 @@ Requires Node.js 22.5 or newer.
8
8
 
9
9
  ## Quick start
10
10
 
11
+ ```bash
12
+ npm install -g @fadhilp/stateql
13
+ ```
14
+
11
15
  Connect to an existing SQLite database, then run a filtered, parameterized
12
16
  query. Parameters keep values separate from SQL; `ORDER BY` makes paging
13
17
  stable, while `LIMIT` bounds work at the database.
14
18
 
15
19
  ```bash
16
- npm install --global stateql
17
20
  export STQL_SESSION=audit
18
21
  stql profile add local ./app.sqlite
19
22
  stql connect local
@@ -61,17 +64,23 @@ Example first page:
61
64
  Running the same normalized query with the same parameters reuses `q_1` while
62
65
  its cache is valid. Use `--cache bypass` when a fresh read is required.
63
66
 
64
- PostgreSQL credentials should come from an environment variable:
67
+ PostgreSQL and MySQL credentials should come from environment variables:
65
68
 
66
69
  ```bash
67
70
  export APP_DATABASE_URL='postgres://user:password@host/app'
68
71
  stql connect --env APP_DATABASE_URL --name app --read-only
72
+
73
+ export MYSQL_DATABASE_URL='mysql://user:password@host/app'
74
+ stql connect --env MYSQL_DATABASE_URL --name mysql-app --read-only
69
75
  ```
70
76
 
77
+ MySQL uses positional `?` parameters. MariaDB compatibility is not currently
78
+ claimed.
79
+
71
80
  ## Commands
72
81
 
73
82
  ```text
74
- stql connect <sqlite-path|postgres-url> [--name NAME] [--env ENV] [--read-write]
83
+ stql connect <sqlite-path|postgres-url|mysql-url> [--name NAME] [--env ENV] [--read-write]
75
84
  stql connect --profile NAME
76
85
  stql status
77
86
  stql profile add|list|show|remove
@@ -94,6 +103,13 @@ stql batch [commands.json|commands.jsonl|-] [--continue-on-error]
94
103
  stql pipe [--continue-on-error]
95
104
  ```
96
105
 
106
+ Database commands accept `--timeout-ms N`; default is 30,000 ms. `Ctrl+C`
107
+ cancels active work. SQLite runs in a killable child process so long synchronous
108
+ statements cannot block StateQL's event loop. PostgreSQL uses server-side
109
+ `statement_timeout` plus client deadlines. MySQL deadlines destroy the active
110
+ connection. A timed-out write may return `OUTCOME_UNKNOWN` when commit status
111
+ cannot be proven.
112
+
97
113
  ## Output modes
98
114
 
99
115
  CLI output defaults to compact, one-line `agent` JSON. Successes flatten useful
@@ -173,25 +189,31 @@ Run the array with `stql batch commands.json`. Batch fields use snake case;
173
189
  supported command names match CLI paths, such as `filter`,
174
190
  `transaction.begin`, `session.summary`, `alias.set`, `plan`, and `apply`.
175
191
  Batch filters use `where` for the predicate and may assign the derived result
176
- with `as`.
192
+ with `as`. Database commands may set `timeout_ms`; otherwise they use the
193
+ 30-second default.
177
194
 
178
195
  State metadata lives under `STQL_HOME`, or the platform data directory when
179
196
  unset. Set `STQL_SESSION` to select a named session.
180
197
 
181
198
  Read cache entries expire after five minutes; materialized handles expire after
182
- 24 hours. Queries exceeding 10,000 rows fail before materialization; add a
183
- narrower `WHERE` clause or `LIMIT`. Command history keeps the latest 10,000
184
- entries per session. SQLite cache reuse also checks
185
- the database file signature; PostgreSQL reuse is labeled `ttl_based`, never
186
- authoritative. Transactions are staged in local state so they survive CLI
187
- invocations, then executed atomically on commit. Connections cannot be changed
188
- or disconnected while a transaction is active. SQLite supports `serializable`;
189
- PostgreSQL also supports `repeatable read`, `read committed`, and
190
- `read uncommitted`. PostgreSQL reads run inside database-enforced read-only
191
- transactions.
192
-
193
- StateQL stores no PostgreSQL password. Credential-bearing URLs must be supplied
194
- through `--env`. SQLite result rows are materialized locally for durable access.
199
+ 24 hours. Expired results and plans are deleted when StateQL next opens. Queries
200
+ exceeding 10,000 rows or 16 MiB of serialized row data fail before persistence;
201
+ add a narrower `WHERE` clause, `LIMIT`, or smaller column selection. These caps
202
+ bound persisted materialization, while the independent deadline bounds execution
203
+ time. Command history keeps the latest 10,000 entries per session. SQLite cache reuse also checks
204
+ the database file signature; PostgreSQL and MySQL reuse is labeled `ttl_based`,
205
+ never authoritative. Transactions are staged in local state so they survive CLI
206
+ invocations, then executed atomically on commit. Database reads, plans,
207
+ connection changes, and disconnects are rejected while a transaction is active;
208
+ commit or roll back first. SQLite supports `serializable`;
209
+ PostgreSQL and MySQL also support `repeatable read`, `read committed`, and
210
+ `read uncommitted`. Server reads run inside database-enforced read-only
211
+ transactions. MySQL staged transactions reject DDL because MySQL implicitly
212
+ commits those statements.
213
+
214
+ StateQL stores no PostgreSQL or MySQL password. Credential-bearing URLs must be
215
+ supplied through `--env`. SQLite result rows are materialized locally for
216
+ durable access.
195
217
  `filter` evaluates one scalar SQLite predicate against those stored rows, keeps
196
218
  source order, state metadata, and expiry, and never accesses the original
197
219
  database. Use parameters for values. Subqueries, query-shaping clauses, and
@@ -209,10 +231,18 @@ Interrupted commits remain fail-closed; stale `committing` records become
209
231
  ## Library
210
232
 
211
233
  ```ts
212
- import { StateQL } from "stateql";
213
-
214
- const stateql = new StateQL({ home: "./.stql" });
215
- const response = await stateql.query("SELECT * FROM users");
234
+ import { StateQL } from "@fadhilp/stateql";
235
+
236
+ const stateql = new StateQL({
237
+ home: "./.stql",
238
+ timeoutMs: 30_000,
239
+ maxResultBytes: 16 * 1024 * 1024,
240
+ });
241
+ const controller = new AbortController();
242
+ const response = await stateql.query("SELECT * FROM users", {
243
+ signal: controller.signal,
244
+ timeoutMs: 5_000,
245
+ });
216
246
  if (response.ok) {
217
247
  const handle = (response.data as { result_id: string }).result_id;
218
248
  await stateql.filter(handle, "email LIKE ?", {
@@ -7,10 +7,23 @@ export interface ReadResult {
7
7
  export interface WriteResult {
8
8
  affectedRows: number;
9
9
  }
10
+ export interface AdapterContext {
11
+ deadline: number;
12
+ signal?: AbortSignal;
13
+ }
14
+ export declare class AdapterExecutionError extends Error {
15
+ readonly reason: "timeout" | "aborted";
16
+ readonly outcomeUnknown: boolean;
17
+ constructor(message: string, reason: "timeout" | "aborted", outcomeUnknown: boolean);
18
+ }
10
19
  export declare class BatchWriteError extends Error {
11
20
  readonly outcomeUnknown: boolean;
12
21
  constructor(message: string, outcomeUnknown: boolean);
13
22
  }
23
+ export declare class AdapterWriteError extends Error {
24
+ readonly outcomeUnknown: boolean;
25
+ constructor(message: string, outcomeUnknown: boolean);
26
+ }
14
27
  export interface Adapter {
15
28
  readonly confidence: StateConfidence;
16
29
  read(sql: string, params: SqlParameters): Promise<ReadResult>;
@@ -20,4 +33,5 @@ export interface Adapter {
20
33
  inspect(kind: string, table?: string): Promise<unknown>;
21
34
  close(): Promise<void>;
22
35
  }
23
- export declare function createAdapter(connection: ConnectionRecord): Promise<Adapter>;
36
+ export declare function createAdapterContext(timeoutMs: number, signal?: AbortSignal): AdapterContext;
37
+ export declare function createAdapter(connection: ConnectionRecord, context: AdapterContext): Promise<Adapter>;