camusdb 0.1.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/LICENSE +21 -0
- package/README.md +950 -0
- package/dist/auth/credentials.d.ts +30 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +23 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/auth/login-client.d.ts +37 -0
- package/dist/auth/login-client.d.ts.map +1 -0
- package/dist/auth/login-client.js +8 -0
- package/dist/auth/login-client.js.map +1 -0
- package/dist/auth/rest-login-client.d.ts +17 -0
- package/dist/auth/rest-login-client.d.ts.map +1 -0
- package/dist/auth/rest-login-client.js +71 -0
- package/dist/auth/rest-login-client.js.map +1 -0
- package/dist/auth/token-provider.d.ts +123 -0
- package/dist/auth/token-provider.d.ts.map +1 -0
- package/dist/auth/token-provider.js +209 -0
- package/dist/auth/token-provider.js.map +1 -0
- package/dist/backup.d.ts +98 -0
- package/dist/backup.d.ts.map +1 -0
- package/dist/backup.js +153 -0
- package/dist/backup.js.map +1 -0
- package/dist/cache.d.ts +90 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +121 -0
- package/dist/cache.js.map +1 -0
- package/dist/client.d.ts +406 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +724 -0
- package/dist/client.js.map +1 -0
- package/dist/column-type.d.ts +33 -0
- package/dist/column-type.d.ts.map +1 -0
- package/dist/column-type.js +50 -0
- package/dist/column-type.js.map +1 -0
- package/dist/column-value.d.ts +77 -0
- package/dist/column-value.d.ts.map +1 -0
- package/dist/column-value.js +60 -0
- package/dist/column-value.js.map +1 -0
- package/dist/config.d.ts +181 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +315 -0
- package/dist/config.js.map +1 -0
- package/dist/connection-string.d.ts +45 -0
- package/dist/connection-string.d.ts.map +1 -0
- package/dist/connection-string.js +170 -0
- package/dist/connection-string.js.map +1 -0
- package/dist/endpoint-pool.d.ts +70 -0
- package/dist/endpoint-pool.d.ts.map +1 -0
- package/dist/endpoint-pool.js +120 -0
- package/dist/endpoint-pool.js.map +1 -0
- package/dist/error-codes.d.ts +44 -0
- package/dist/error-codes.d.ts.map +1 -0
- package/dist/error-codes.js +43 -0
- package/dist/error-codes.js.map +1 -0
- package/dist/errors.d.ts +24 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/hlc.d.ts +19 -0
- package/dist/hlc.d.ts.map +1 -0
- package/dist/hlc.js +11 -0
- package/dist/hlc.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +41 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +345 -0
- package/dist/json.js.map +1 -0
- package/dist/object-id.d.ts +39 -0
- package/dist/object-id.d.ts.map +1 -0
- package/dist/object-id.js +99 -0
- package/dist/object-id.js.map +1 -0
- package/dist/options.d.ts +77 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +68 -0
- package/dist/options.js.map +1 -0
- package/dist/prepared/binder.d.ts +20 -0
- package/dist/prepared/binder.d.ts.map +1 -0
- package/dist/prepared/binder.js +32 -0
- package/dist/prepared/binder.js.map +1 -0
- package/dist/prepared/policy.d.ts +81 -0
- package/dist/prepared/policy.d.ts.map +1 -0
- package/dist/prepared/policy.js +164 -0
- package/dist/prepared/policy.js.map +1 -0
- package/dist/query-stream.d.ts +55 -0
- package/dist/query-stream.d.ts.map +1 -0
- package/dist/query-stream.js +94 -0
- package/dist/query-stream.js.map +1 -0
- package/dist/result-set.d.ts +62 -0
- package/dist/result-set.d.ts.map +1 -0
- package/dist/result-set.js +100 -0
- package/dist/result-set.js.map +1 -0
- package/dist/retry.d.ts +38 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +93 -0
- package/dist/retry.js.map +1 -0
- package/dist/routing/advice.d.ts +63 -0
- package/dist/routing/advice.d.ts.map +1 -0
- package/dist/routing/advice.js +61 -0
- package/dist/routing/advice.js.map +1 -0
- package/dist/routing/route-cache.d.ts +53 -0
- package/dist/routing/route-cache.d.ts.map +1 -0
- package/dist/routing/route-cache.js +123 -0
- package/dist/routing/route-cache.js.map +1 -0
- package/dist/routing/router.d.ts +53 -0
- package/dist/routing/router.d.ts.map +1 -0
- package/dist/routing/router.js +89 -0
- package/dist/routing/router.js.map +1 -0
- package/dist/row-source.d.ts +48 -0
- package/dist/row-source.d.ts.map +1 -0
- package/dist/row-source.js +35 -0
- package/dist/row-source.js.map +1 -0
- package/dist/runtime.d.ts +58 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +137 -0
- package/dist/runtime.js.map +1 -0
- package/dist/shared-registry.d.ts +32 -0
- package/dist/shared-registry.d.ts.map +1 -0
- package/dist/shared-registry.js +48 -0
- package/dist/shared-registry.js.map +1 -0
- package/dist/sql-syntax.d.ts +44 -0
- package/dist/sql-syntax.d.ts.map +1 -0
- package/dist/sql-syntax.js +83 -0
- package/dist/sql-syntax.js.map +1 -0
- package/dist/statements.d.ts +15 -0
- package/dist/statements.d.ts.map +1 -0
- package/dist/statements.js +90 -0
- package/dist/statements.js.map +1 -0
- package/dist/transaction.d.ts +117 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +204 -0
- package/dist/transaction.js.map +1 -0
- package/dist/transport/authenticating-transport.d.ts +63 -0
- package/dist/transport/authenticating-transport.d.ts.map +1 -0
- package/dist/transport/authenticating-transport.js +119 -0
- package/dist/transport/authenticating-transport.js.map +1 -0
- package/dist/transport/branch-statements.d.ts +39 -0
- package/dist/transport/branch-statements.d.ts.map +1 -0
- package/dist/transport/branch-statements.js +74 -0
- package/dist/transport/branch-statements.js.map +1 -0
- package/dist/transport/error-text.d.ts +26 -0
- package/dist/transport/error-text.d.ts.map +1 -0
- package/dist/transport/error-text.js +75 -0
- package/dist/transport/error-text.js.map +1 -0
- package/dist/transport/grpc/batcher.d.ts +127 -0
- package/dist/transport/grpc/batcher.d.ts.map +1 -0
- package/dist/transport/grpc/batcher.js +399 -0
- package/dist/transport/grpc/batcher.js.map +1 -0
- package/dist/transport/grpc/codec.d.ts +40 -0
- package/dist/transport/grpc/codec.d.ts.map +1 -0
- package/dist/transport/grpc/codec.js +231 -0
- package/dist/transport/grpc/codec.js.map +1 -0
- package/dist/transport/grpc/grpc-transport.d.ts +115 -0
- package/dist/transport/grpc/grpc-transport.d.ts.map +1 -0
- package/dist/transport/grpc/grpc-transport.js +577 -0
- package/dist/transport/grpc/grpc-transport.js.map +1 -0
- package/dist/transport/grpc/messages.d.ts +221 -0
- package/dist/transport/grpc/messages.d.ts.map +1 -0
- package/dist/transport/grpc/messages.js +56 -0
- package/dist/transport/grpc/messages.js.map +1 -0
- package/dist/transport/grpc/proto.d.ts +71 -0
- package/dist/transport/grpc/proto.d.ts.map +1 -0
- package/dist/transport/grpc/proto.js +67 -0
- package/dist/transport/grpc/proto.js.map +1 -0
- package/dist/transport/http.d.ts +62 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +169 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/transport/ndjson-row-source.d.ts +38 -0
- package/dist/transport/ndjson-row-source.d.ts.map +1 -0
- package/dist/transport/ndjson-row-source.js +197 -0
- package/dist/transport/ndjson-row-source.js.map +1 -0
- package/dist/transport/rest-decode.d.ts +33 -0
- package/dist/transport/rest-decode.d.ts.map +1 -0
- package/dist/transport/rest-decode.js +162 -0
- package/dist/transport/rest-decode.js.map +1 -0
- package/dist/transport/rest-prepared-cache.d.ts +50 -0
- package/dist/transport/rest-prepared-cache.d.ts.map +1 -0
- package/dist/transport/rest-prepared-cache.js +101 -0
- package/dist/transport/rest-prepared-cache.js.map +1 -0
- package/dist/transport/rest-transport.d.ts +88 -0
- package/dist/transport/rest-transport.d.ts.map +1 -0
- package/dist/transport/rest-transport.js +388 -0
- package/dist/transport/rest-transport.js.map +1 -0
- package/dist/transport/transport-pool.d.ts +40 -0
- package/dist/transport/transport-pool.d.ts.map +1 -0
- package/dist/transport/transport-pool.js +48 -0
- package/dist/transport/transport-pool.js.map +1 -0
- package/dist/transport/transport.d.ts +199 -0
- package/dist/transport/transport.d.ts.map +1 -0
- package/dist/transport/transport.js +11 -0
- package/dist/transport/transport.js.map +1 -0
- package/dist/values/decode.d.ts +39 -0
- package/dist/values/decode.d.ts.map +1 -0
- package/dist/values/decode.js +75 -0
- package/dist/values/decode.js.map +1 -0
- package/dist/values/encode.d.ts +45 -0
- package/dist/values/encode.d.ts.map +1 -0
- package/dist/values/encode.js +271 -0
- package/dist/values/encode.js.map +1 -0
- package/dist/values/ticks.d.ts +31 -0
- package/dist/values/ticks.d.ts.map +1 -0
- package/dist/values/ticks.js +52 -0
- package/dist/values/ticks.js.map +1 -0
- package/dist/values/typed.d.ts +67 -0
- package/dist/values/typed.d.ts.map +1 -0
- package/dist/values/typed.js +134 -0
- package/dist/values/typed.js.map +1 -0
- package/dist/values/uuid.d.ts +27 -0
- package/dist/values/uuid.d.ts.map +1 -0
- package/dist/values/uuid.js +76 -0
- package/dist/values/uuid.js.map +1 -0
- package/dist/vector.d.ts +26 -0
- package/dist/vector.d.ts.map +1 -0
- package/dist/vector.js +48 -0
- package/dist/vector.js.map +1 -0
- package/package.json +86 -0
- package/proto/camus_sql.proto +566 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,+FAA+F;IAC/F,aAAa,EAAE,eAAe;IAE9B;;;OAGG;IACH,YAAY,EAAE,cAAc;CACpB,CAAC;AAIX,uCAAuC;AACvC,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,+DAA+D;IAC/D,SAAS,EAAE,WAAW;IAEtB;;;OAGG;IACH,QAAQ,EAAE,UAAU;CACZ,CAAC;AAIX,yFAAyF;AACzF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;;;OAGG;IACH,WAAW,EAAE,aAAa;IAE1B;;;;;OAKG;IACH,UAAU,EAAE,YAAY;CAChB,CAAC;AA0BX,oEAAoE;AACpE,MAAM,CAAC,MAAM,2BAA2B,GAA4B,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAEtF,wEAAwE;AACxE,MAAM,CAAC,MAAM,8BAA8B,GAA4B,MAAM,CAAC,MAAM,CAAC;IACnF,OAAO,EAAE,YAAY,CAAC,UAAU;CACjC,CAAC,CAAC;AAEH,mEAAmE;AACnE,MAAM,CAAC,MAAM,4BAA4B,GAA4B,MAAM,CAAC,MAAM,CAAC;IACjF,cAAc,EAAE,mBAAmB,CAAC,YAAY;IAChD,IAAI,EAAE,oBAAoB,CAAC,QAAQ;CACpC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,MAAM,UAAU,YAAY,CAC1B,OAAgC,EAChC,QAA6C;IAE7C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAE3C,OAAO;QACL,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,QAAQ,CAAC,cAAc;QACjE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI;QACnC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;QAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;KAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import type { ColumnValue } from '../column-value.js';
|
|
8
|
+
/**
|
|
9
|
+
* Orders a call's parameter values the way a prepared statement binds them.
|
|
10
|
+
*
|
|
11
|
+
* The server publishes the statement's placeholder names in binding order when it registers the
|
|
12
|
+
* statement. Every later execution then sends only values, positionally, so neither the SQL nor
|
|
13
|
+
* the names travel again. This function is where a named map becomes that ordered list.
|
|
14
|
+
*
|
|
15
|
+
* A placeholder with no bound value is an error rather than a null. The statement declares it, so
|
|
16
|
+
* a missing value is a mistake in the call, and sending a null would run the statement against a
|
|
17
|
+
* value the caller never wrote.
|
|
18
|
+
*/
|
|
19
|
+
export declare function bindPositional(parameterNames: readonly string[], parameters: ReadonlyMap<string, ColumnValue> | undefined): ColumnValue[];
|
|
20
|
+
//# sourceMappingURL=binder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binder.d.ts","sourceRoot":"","sources":["../../src/prepared/binder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,cAAc,EAAE,SAAS,MAAM,EAAE,EACjC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,SAAS,GACvD,WAAW,EAAE,CAkBf"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import { CamusError } from '../errors.js';
|
|
8
|
+
import { CamusErrorCode } from '../error-codes.js';
|
|
9
|
+
/**
|
|
10
|
+
* Orders a call's parameter values the way a prepared statement binds them.
|
|
11
|
+
*
|
|
12
|
+
* The server publishes the statement's placeholder names in binding order when it registers the
|
|
13
|
+
* statement. Every later execution then sends only values, positionally, so neither the SQL nor
|
|
14
|
+
* the names travel again. This function is where a named map becomes that ordered list.
|
|
15
|
+
*
|
|
16
|
+
* A placeholder with no bound value is an error rather than a null. The statement declares it, so
|
|
17
|
+
* a missing value is a mistake in the call, and sending a null would run the statement against a
|
|
18
|
+
* value the caller never wrote.
|
|
19
|
+
*/
|
|
20
|
+
export function bindPositional(parameterNames, parameters) {
|
|
21
|
+
const values = new Array(parameterNames.length);
|
|
22
|
+
for (let i = 0; i < parameterNames.length; i++) {
|
|
23
|
+
const name = parameterNames[i];
|
|
24
|
+
const value = parameters?.get(name);
|
|
25
|
+
if (value === undefined) {
|
|
26
|
+
throw new CamusError(CamusErrorCode.InvalidParameter, `The prepared statement declares the parameter '${name}' but no value was bound for it.`);
|
|
27
|
+
}
|
|
28
|
+
values[i] = value;
|
|
29
|
+
}
|
|
30
|
+
return values;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=binder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binder.js","sourceRoot":"","sources":["../../src/prepared/binder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAC5B,cAAiC,EACjC,UAAwD;IAExD,MAAM,MAAM,GAAkB,IAAI,KAAK,CAAc,cAAc,CAAC,MAAM,CAAC,CAAC;IAE5E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,CAAE,CAAC;QAChC,MAAM,KAAK,GAAG,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAEpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,gBAAgB,EAC/B,kDAAkD,IAAI,kCAAkC,CACzF,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;IACpB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
/** What the policy decided about one execution of a statement. */
|
|
8
|
+
export declare const PrepareDecision: {
|
|
9
|
+
/** Run it inline. It is not hot enough yet, or it cannot be prepared. */
|
|
10
|
+
readonly No: "no";
|
|
11
|
+
/** Register it now, then run this execution prepared. */
|
|
12
|
+
readonly Register: "register";
|
|
13
|
+
/** It is already registered. Run this execution prepared. */
|
|
14
|
+
readonly Yes: "yes";
|
|
15
|
+
};
|
|
16
|
+
export type PrepareDecision = (typeof PrepareDecision)[keyof typeof PrepareDecision];
|
|
17
|
+
/** A statement the policy evicted, so the server can stop holding a handle nobody uses. */
|
|
18
|
+
export interface EvictedStatement {
|
|
19
|
+
readonly database: string;
|
|
20
|
+
readonly sql: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Which statements a client prepares.
|
|
24
|
+
*
|
|
25
|
+
* Preparing costs one extra round trip and saves the SQL text and the parameter names on every
|
|
26
|
+
* execution after it, so it pays for a statement that runs many times and wastes a round trip for
|
|
27
|
+
* one that runs once. The policy is that counting: a statement is registered once it has been seen
|
|
28
|
+
* `minUsages` times, and the `maxAutoPrepare` most recently used registrations are kept.
|
|
29
|
+
*
|
|
30
|
+
* The policy is shared per deployment and settings rather than owned by one client. Which
|
|
31
|
+
* statements a workload repeats is a property of the workload, and an application that builds a
|
|
32
|
+
* client per request would restart the counting every time and never conclude anything.
|
|
33
|
+
*
|
|
34
|
+
* Recency is a `Map`, which preserves insertion order: re-inserting a key moves it to the end, so
|
|
35
|
+
* the first key the map yields is the least recently used one.
|
|
36
|
+
*/
|
|
37
|
+
export declare class CamusPreparedStatementPolicy {
|
|
38
|
+
static readonly DEFAULT_MAX_AUTO_PREPARE = 128;
|
|
39
|
+
static readonly DEFAULT_MIN_USAGES = 2;
|
|
40
|
+
private static readonly shared;
|
|
41
|
+
/** The process-wide policy for a deployment-and-settings key. */
|
|
42
|
+
static forKey(key: string, factory: () => CamusPreparedStatementPolicy): CamusPreparedStatementPolicy;
|
|
43
|
+
/** @internal Test hook: drops every shared policy. */
|
|
44
|
+
static resetShared(): void;
|
|
45
|
+
readonly maxAutoPrepare: number;
|
|
46
|
+
readonly minUsages: number;
|
|
47
|
+
private readonly entries;
|
|
48
|
+
private disabled;
|
|
49
|
+
constructor(maxAutoPrepare: number, minUsages: number);
|
|
50
|
+
/** True when automatic preparation is off, either by configuration or because a server refused. */
|
|
51
|
+
get isDisabled(): boolean;
|
|
52
|
+
/** How many statements are currently kept prepared. */
|
|
53
|
+
get preparedCount(): number;
|
|
54
|
+
/** Whether one statement is currently kept prepared. */
|
|
55
|
+
isPrepared(database: string, sql: string): boolean;
|
|
56
|
+
/** Decides what this execution should do, and reports a statement the decision evicted. */
|
|
57
|
+
decide(database: string, sql: string): {
|
|
58
|
+
decision: PrepareDecision;
|
|
59
|
+
evicted?: EvictedStatement;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Marks a statement for registration because the caller asked for it directly.
|
|
63
|
+
*
|
|
64
|
+
* An explicit request overrides an earlier refusal: the caller may well have fixed whatever made
|
|
65
|
+
* it fail, and it is asking rather than being guessed at.
|
|
66
|
+
*/
|
|
67
|
+
pin(database: string, sql: string): {
|
|
68
|
+
decision: PrepareDecision;
|
|
69
|
+
evicted?: EvictedStatement;
|
|
70
|
+
};
|
|
71
|
+
/** Records that the server registered a statement. */
|
|
72
|
+
markPrepared(database: string, sql: string): void;
|
|
73
|
+
/** Records that this statement should not be offered for registration again. */
|
|
74
|
+
markRefused(database: string, sql: string): void;
|
|
75
|
+
/** Stops offering any statement for registration. Used when a server has no support at all. */
|
|
76
|
+
disable(): void;
|
|
77
|
+
/** Drops what is known about a statement, so it is reconsidered from the start. */
|
|
78
|
+
forget(database: string, sql: string): void;
|
|
79
|
+
private touch;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/prepared/policy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,kEAAkE;AAClE,eAAO,MAAM,eAAe;IAC1B,yEAAyE;;IAEzE,yDAAyD;;IAEzD,6DAA6D;;CAErD,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAkBrF,2FAA2F;AAC3F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,4BAA4B;IACvC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,OAAO;IAE/C,MAAM,CAAC,QAAQ,CAAC,kBAAkB,KAAK;IAEvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAsD;IAEpF,iEAAiE;IACjE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,4BAA4B,GAAG,4BAA4B;IAIrG,sDAAsD;IACtD,MAAM,CAAC,WAAW,IAAI,IAAI;IAI1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IAEpD,OAAO,CAAC,QAAQ,CAAU;gBAEd,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAMrD,mGAAmG;IACnG,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,uDAAuD;IACvD,IAAI,aAAa,IAAI,MAAM,CAQ1B;IAED,wDAAwD;IACxD,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAIlD,2FAA2F;IAC3F,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,eAAe,CAAC;QAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;KAAE;IA2BhG;;;;;OAKG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,eAAe,CAAC;QAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;KAAE;IAa7F,sDAAsD;IACtD,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKjD,gFAAgF;IAChF,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKhD,+FAA+F;IAC/F,OAAO,IAAI,IAAI;IAIf,mFAAmF;IACnF,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAI3C,OAAO,CAAC,KAAK;CAiCd"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import { SharedRegistry } from '../shared-registry.js';
|
|
8
|
+
/** What the policy decided about one execution of a statement. */
|
|
9
|
+
export const PrepareDecision = {
|
|
10
|
+
/** Run it inline. It is not hot enough yet, or it cannot be prepared. */
|
|
11
|
+
No: 'no',
|
|
12
|
+
/** Register it now, then run this execution prepared. */
|
|
13
|
+
Register: 'register',
|
|
14
|
+
/** It is already registered. Run this execution prepared. */
|
|
15
|
+
Yes: 'yes',
|
|
16
|
+
};
|
|
17
|
+
const EntryState = {
|
|
18
|
+
Counting: 0,
|
|
19
|
+
Registering: 1,
|
|
20
|
+
Prepared: 2,
|
|
21
|
+
Refused: 3,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Which statements a client prepares.
|
|
25
|
+
*
|
|
26
|
+
* Preparing costs one extra round trip and saves the SQL text and the parameter names on every
|
|
27
|
+
* execution after it, so it pays for a statement that runs many times and wastes a round trip for
|
|
28
|
+
* one that runs once. The policy is that counting: a statement is registered once it has been seen
|
|
29
|
+
* `minUsages` times, and the `maxAutoPrepare` most recently used registrations are kept.
|
|
30
|
+
*
|
|
31
|
+
* The policy is shared per deployment and settings rather than owned by one client. Which
|
|
32
|
+
* statements a workload repeats is a property of the workload, and an application that builds a
|
|
33
|
+
* client per request would restart the counting every time and never conclude anything.
|
|
34
|
+
*
|
|
35
|
+
* Recency is a `Map`, which preserves insertion order: re-inserting a key moves it to the end, so
|
|
36
|
+
* the first key the map yields is the least recently used one.
|
|
37
|
+
*/
|
|
38
|
+
export class CamusPreparedStatementPolicy {
|
|
39
|
+
static DEFAULT_MAX_AUTO_PREPARE = 128;
|
|
40
|
+
static DEFAULT_MIN_USAGES = 2;
|
|
41
|
+
static shared = new SharedRegistry();
|
|
42
|
+
/** The process-wide policy for a deployment-and-settings key. */
|
|
43
|
+
static forKey(key, factory) {
|
|
44
|
+
return CamusPreparedStatementPolicy.shared.get(key, factory);
|
|
45
|
+
}
|
|
46
|
+
/** @internal Test hook: drops every shared policy. */
|
|
47
|
+
static resetShared() {
|
|
48
|
+
CamusPreparedStatementPolicy.shared.clear();
|
|
49
|
+
}
|
|
50
|
+
maxAutoPrepare;
|
|
51
|
+
minUsages;
|
|
52
|
+
entries = new Map();
|
|
53
|
+
disabled;
|
|
54
|
+
constructor(maxAutoPrepare, minUsages) {
|
|
55
|
+
this.maxAutoPrepare = maxAutoPrepare;
|
|
56
|
+
this.minUsages = Math.max(1, minUsages);
|
|
57
|
+
this.disabled = maxAutoPrepare <= 0;
|
|
58
|
+
}
|
|
59
|
+
/** True when automatic preparation is off, either by configuration or because a server refused. */
|
|
60
|
+
get isDisabled() {
|
|
61
|
+
return this.disabled;
|
|
62
|
+
}
|
|
63
|
+
/** How many statements are currently kept prepared. */
|
|
64
|
+
get preparedCount() {
|
|
65
|
+
let count = 0;
|
|
66
|
+
for (const entry of this.entries.values()) {
|
|
67
|
+
if (entry.state === EntryState.Prepared)
|
|
68
|
+
count++;
|
|
69
|
+
}
|
|
70
|
+
return count;
|
|
71
|
+
}
|
|
72
|
+
/** Whether one statement is currently kept prepared. */
|
|
73
|
+
isPrepared(database, sql) {
|
|
74
|
+
return this.entries.get(key(database, sql))?.state === EntryState.Prepared;
|
|
75
|
+
}
|
|
76
|
+
/** Decides what this execution should do, and reports a statement the decision evicted. */
|
|
77
|
+
decide(database, sql) {
|
|
78
|
+
if (this.disabled)
|
|
79
|
+
return { decision: PrepareDecision.No };
|
|
80
|
+
const { entry, evicted } = this.touch(database, sql);
|
|
81
|
+
switch (entry.state) {
|
|
82
|
+
case EntryState.Prepared:
|
|
83
|
+
return { decision: PrepareDecision.Yes, ...(evicted ? { evicted } : {}) };
|
|
84
|
+
case EntryState.Refused:
|
|
85
|
+
return { decision: PrepareDecision.No, ...(evicted ? { evicted } : {}) };
|
|
86
|
+
case EntryState.Registering:
|
|
87
|
+
// A registration is already in flight. Running inline meanwhile is correct rather than
|
|
88
|
+
// merely tolerable: the statement is not registered yet.
|
|
89
|
+
return { decision: PrepareDecision.No, ...(evicted ? { evicted } : {}) };
|
|
90
|
+
default:
|
|
91
|
+
if (++entry.usages < this.minUsages) {
|
|
92
|
+
return { decision: PrepareDecision.No, ...(evicted ? { evicted } : {}) };
|
|
93
|
+
}
|
|
94
|
+
entry.state = EntryState.Registering;
|
|
95
|
+
return { decision: PrepareDecision.Register, ...(evicted ? { evicted } : {}) };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Marks a statement for registration because the caller asked for it directly.
|
|
100
|
+
*
|
|
101
|
+
* An explicit request overrides an earlier refusal: the caller may well have fixed whatever made
|
|
102
|
+
* it fail, and it is asking rather than being guessed at.
|
|
103
|
+
*/
|
|
104
|
+
pin(database, sql) {
|
|
105
|
+
const { entry, evicted } = this.touch(database, sql);
|
|
106
|
+
if (entry.state === EntryState.Prepared) {
|
|
107
|
+
return { decision: PrepareDecision.Yes, ...(evicted ? { evicted } : {}) };
|
|
108
|
+
}
|
|
109
|
+
entry.state = EntryState.Registering;
|
|
110
|
+
entry.usages = Math.max(entry.usages, this.minUsages);
|
|
111
|
+
return { decision: PrepareDecision.Register, ...(evicted ? { evicted } : {}) };
|
|
112
|
+
}
|
|
113
|
+
/** Records that the server registered a statement. */
|
|
114
|
+
markPrepared(database, sql) {
|
|
115
|
+
const entry = this.entries.get(key(database, sql));
|
|
116
|
+
if (entry !== undefined)
|
|
117
|
+
entry.state = EntryState.Prepared;
|
|
118
|
+
}
|
|
119
|
+
/** Records that this statement should not be offered for registration again. */
|
|
120
|
+
markRefused(database, sql) {
|
|
121
|
+
const entry = this.entries.get(key(database, sql));
|
|
122
|
+
if (entry !== undefined)
|
|
123
|
+
entry.state = EntryState.Refused;
|
|
124
|
+
}
|
|
125
|
+
/** Stops offering any statement for registration. Used when a server has no support at all. */
|
|
126
|
+
disable() {
|
|
127
|
+
this.disabled = true;
|
|
128
|
+
}
|
|
129
|
+
/** Drops what is known about a statement, so it is reconsidered from the start. */
|
|
130
|
+
forget(database, sql) {
|
|
131
|
+
this.entries.delete(key(database, sql));
|
|
132
|
+
}
|
|
133
|
+
touch(database, sql) {
|
|
134
|
+
const entryKey = key(database, sql);
|
|
135
|
+
const existing = this.entries.get(entryKey);
|
|
136
|
+
if (existing !== undefined) {
|
|
137
|
+
// Re-inserting moves the key to the end of the map's order, which is the recency list.
|
|
138
|
+
this.entries.delete(entryKey);
|
|
139
|
+
this.entries.set(entryKey, existing);
|
|
140
|
+
return { entry: existing };
|
|
141
|
+
}
|
|
142
|
+
let evicted;
|
|
143
|
+
if (this.entries.size >= this.maxAutoPrepare) {
|
|
144
|
+
const oldestKey = this.entries.keys().next().value;
|
|
145
|
+
if (oldestKey !== undefined) {
|
|
146
|
+
const oldest = this.entries.get(oldestKey);
|
|
147
|
+
this.entries.delete(oldestKey);
|
|
148
|
+
// Only a registered statement is worth telling the caller about. The rest were never more
|
|
149
|
+
// than a counter.
|
|
150
|
+
if (oldest.state === EntryState.Prepared) {
|
|
151
|
+
evicted = { database: oldest.database, sql: oldest.sql };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const entry = { database, sql, usages: 0, state: EntryState.Counting };
|
|
156
|
+
this.entries.set(entryKey, entry);
|
|
157
|
+
return { entry, ...(evicted ? { evicted } : {}) };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// A newline cannot appear in a database name, so it separates the two parts without ambiguity.
|
|
161
|
+
function key(database, sql) {
|
|
162
|
+
return `${database}\n${sql}`;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/prepared/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import type { CamusColumn } from './result-set.js';
|
|
8
|
+
import type { CamusRowSource } from './row-source.js';
|
|
9
|
+
import type { DecodeOptions } from './values/decode.js';
|
|
10
|
+
/**
|
|
11
|
+
* Rows delivered one at a time, as an async iterable.
|
|
12
|
+
*
|
|
13
|
+
* Iterate it with `for await`. The iteration owns the underlying response, and releases it when it
|
|
14
|
+
* ends — whether it ran to the last row, was left early with `break`, or was ended by a `throw`.
|
|
15
|
+
* A stream that is never iterated must be released with `close`, or with `await using`.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* const stream = await client.queryStream<Robot>('SELECT * FROM robots');
|
|
19
|
+
*
|
|
20
|
+
* for await (const robot of stream) {
|
|
21
|
+
* console.log(robot.name);
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* The schema is known before the first row, so `columns` can be read straight away.
|
|
26
|
+
*
|
|
27
|
+
* The streaming path gives up the buffered path's transparent retry of a serializable conflict.
|
|
28
|
+
* Rows can reach this side before the statement's own short transaction commits, so a conflict
|
|
29
|
+
* that surfaces late is raised from the iteration rather than retried. Use `query` — or drive an
|
|
30
|
+
* explicit transaction and retry it yourself — when you need that retry.
|
|
31
|
+
*/
|
|
32
|
+
export declare class CamusQueryStream<T = Record<string, unknown>> implements AsyncIterable<T>, AsyncDisposable {
|
|
33
|
+
private readonly source;
|
|
34
|
+
private readonly mapper;
|
|
35
|
+
private consumed;
|
|
36
|
+
private closed;
|
|
37
|
+
/** @internal Built by `CamusClient.queryStream`. */
|
|
38
|
+
constructor(source: CamusRowSource, options: DecodeOptions);
|
|
39
|
+
/** The output columns, known before the first row. */
|
|
40
|
+
get columns(): CamusColumn[];
|
|
41
|
+
/**
|
|
42
|
+
* The property names each row object carries, in column order.
|
|
43
|
+
*
|
|
44
|
+
* They match `columns` except where a query projected the same column name twice: the leftmost
|
|
45
|
+
* keeps the name, and the ones after it take `name_2`, `name_3`, and so on.
|
|
46
|
+
*/
|
|
47
|
+
get columnKeys(): readonly string[];
|
|
48
|
+
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
49
|
+
/** Reads every remaining row into an array. Convenient when the result is known to be small. */
|
|
50
|
+
toArray(): Promise<T[]>;
|
|
51
|
+
/** Releases the underlying response. Safe to call more than once. */
|
|
52
|
+
close(): Promise<void>;
|
|
53
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=query-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-stream.d.ts","sourceRoot":"","sources":["../src/query-stream.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC,EAAE,eAAe;IACrG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IAExC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IAEnC,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,MAAM,CAAS;IAEvB,oDAAoD;gBACxC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa;IAK1D,sDAAsD;IACtD,IAAI,OAAO,IAAI,WAAW,EAAE,CAM3B;IAED;;;;;OAKG;IACH,IAAI,UAAU,IAAI,SAAS,MAAM,EAAE,CAElC;IAEM,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;IAoBjD,gGAAgG;IAC1F,OAAO,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAQ7B,qEAAqE;IAC/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtB,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7C"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import { RowMapper } from './result-set.js';
|
|
8
|
+
import { columnTypeName } from './column-type.js';
|
|
9
|
+
/**
|
|
10
|
+
* Rows delivered one at a time, as an async iterable.
|
|
11
|
+
*
|
|
12
|
+
* Iterate it with `for await`. The iteration owns the underlying response, and releases it when it
|
|
13
|
+
* ends — whether it ran to the last row, was left early with `break`, or was ended by a `throw`.
|
|
14
|
+
* A stream that is never iterated must be released with `close`, or with `await using`.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* const stream = await client.queryStream<Robot>('SELECT * FROM robots');
|
|
18
|
+
*
|
|
19
|
+
* for await (const robot of stream) {
|
|
20
|
+
* console.log(robot.name);
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* The schema is known before the first row, so `columns` can be read straight away.
|
|
25
|
+
*
|
|
26
|
+
* The streaming path gives up the buffered path's transparent retry of a serializable conflict.
|
|
27
|
+
* Rows can reach this side before the statement's own short transaction commits, so a conflict
|
|
28
|
+
* that surfaces late is raised from the iteration rather than retried. Use `query` — or drive an
|
|
29
|
+
* explicit transaction and retry it yourself — when you need that retry.
|
|
30
|
+
*/
|
|
31
|
+
export class CamusQueryStream {
|
|
32
|
+
source;
|
|
33
|
+
mapper;
|
|
34
|
+
consumed = false;
|
|
35
|
+
closed = false;
|
|
36
|
+
/** @internal Built by `CamusClient.queryStream`. */
|
|
37
|
+
constructor(source, options) {
|
|
38
|
+
this.source = source;
|
|
39
|
+
this.mapper = new RowMapper(source.columnNames, options);
|
|
40
|
+
}
|
|
41
|
+
/** The output columns, known before the first row. */
|
|
42
|
+
get columns() {
|
|
43
|
+
return this.source.columnNames.map((name, index) => ({
|
|
44
|
+
name,
|
|
45
|
+
type: this.source.columnTypes[index],
|
|
46
|
+
typeName: columnTypeName(this.source.columnTypes[index]),
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The property names each row object carries, in column order.
|
|
51
|
+
*
|
|
52
|
+
* They match `columns` except where a query projected the same column name twice: the leftmost
|
|
53
|
+
* keeps the name, and the ones after it take `name_2`, `name_3`, and so on.
|
|
54
|
+
*/
|
|
55
|
+
get columnKeys() {
|
|
56
|
+
return this.mapper.columnKeys;
|
|
57
|
+
}
|
|
58
|
+
async *[Symbol.asyncIterator]() {
|
|
59
|
+
if (this.consumed) {
|
|
60
|
+
throw new Error('This query stream was already iterated. Run the query again for a second pass.');
|
|
61
|
+
}
|
|
62
|
+
this.consumed = true;
|
|
63
|
+
try {
|
|
64
|
+
for (;;) {
|
|
65
|
+
const cells = await this.source.next();
|
|
66
|
+
if (cells === undefined)
|
|
67
|
+
return;
|
|
68
|
+
yield this.mapper.map(cells);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
// Reached on a normal end, on `break`, and on a throw, so the response is never left open.
|
|
73
|
+
await this.close();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Reads every remaining row into an array. Convenient when the result is known to be small. */
|
|
77
|
+
async toArray() {
|
|
78
|
+
const rows = [];
|
|
79
|
+
for await (const row of this)
|
|
80
|
+
rows.push(row);
|
|
81
|
+
return rows;
|
|
82
|
+
}
|
|
83
|
+
/** Releases the underlying response. Safe to call more than once. */
|
|
84
|
+
async close() {
|
|
85
|
+
if (this.closed)
|
|
86
|
+
return;
|
|
87
|
+
this.closed = true;
|
|
88
|
+
await this.source.close();
|
|
89
|
+
}
|
|
90
|
+
async [Symbol.asyncDispose]() {
|
|
91
|
+
await this.close();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=query-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-stream.js","sourceRoot":"","sources":["../src/query-stream.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,gBAAgB;IACV,MAAM,CAAiB;IAEvB,MAAM,CAAY;IAE3B,QAAQ,GAAG,KAAK,CAAC;IAEjB,MAAM,GAAG,KAAK,CAAC;IAEvB,oDAAoD;IACpD,YAAY,MAAsB,EAAE,OAAsB;QACxD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED,sDAAsD;IACtD,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACnD,IAAI;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAE;YACrC,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAE,CAAC;SAC1D,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;;OAKG;IACH,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;QAC3B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,gFAAgF,CAAC,CAAC;QACpG,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC;YACH,SAAS,CAAC;gBACR,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBACvC,IAAI,KAAK,KAAK,SAAS;oBAAE,OAAO;gBAEhC,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAI,KAAK,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,2FAA2F;YAC3F,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,gGAAgG;IAChG,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,GAAQ,EAAE,CAAC;QAErB,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE7C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qEAAqE;IACrE,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QAExB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import { ColumnType } from './column-type.js';
|
|
8
|
+
import type { ColumnValue } from './column-value.js';
|
|
9
|
+
import type { DecodeOptions } from './values/decode.js';
|
|
10
|
+
/** One output column of a query. */
|
|
11
|
+
export interface CamusColumn {
|
|
12
|
+
/** The column name, in the case the query wrote it. */
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/** The declared wire type. */
|
|
15
|
+
readonly type: ColumnType;
|
|
16
|
+
/** The type's name, for display. */
|
|
17
|
+
readonly typeName: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The rows of one query, held positionally.
|
|
21
|
+
*
|
|
22
|
+
* Cells live in a single flat array, row-major: cell `(row, column)` is at
|
|
23
|
+
* `row * columnCount + column`. The column names and declared types come from the response's
|
|
24
|
+
* authoritative schema, so the shape is known even when there are no rows — which is what lets a
|
|
25
|
+
* caller read `columns` before reading a row, and what makes an empty result still describe
|
|
26
|
+
* itself.
|
|
27
|
+
*/
|
|
28
|
+
export declare class CamusResultSet {
|
|
29
|
+
/** An empty result: no rows and no columns. Shared, so a count-only reply allocates nothing. */
|
|
30
|
+
static readonly EMPTY: CamusResultSet;
|
|
31
|
+
readonly columnNames: readonly string[];
|
|
32
|
+
readonly columnTypes: readonly ColumnType[];
|
|
33
|
+
readonly rowCount: number;
|
|
34
|
+
private readonly cells;
|
|
35
|
+
constructor(columnNames: readonly string[], columnTypes: readonly ColumnType[], cells: readonly ColumnValue[], rowCount: number);
|
|
36
|
+
get columnCount(): number;
|
|
37
|
+
/** The output columns, in order. */
|
|
38
|
+
get columns(): CamusColumn[];
|
|
39
|
+
/** One raw cell. */
|
|
40
|
+
cell(row: number, column: number): ColumnValue;
|
|
41
|
+
/** One row as raw cells. */
|
|
42
|
+
rawRow(row: number): ColumnValue[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Turns positional cells into a plain object, keyed by column name.
|
|
46
|
+
*
|
|
47
|
+
* A duplicate column name — which a join projection can produce — keeps the leftmost column, and
|
|
48
|
+
* the ones after it are reachable at `name_2`, `name_3`, and so on. Silently dropping a column
|
|
49
|
+
* would lose data the query asked for.
|
|
50
|
+
*/
|
|
51
|
+
export declare class RowMapper {
|
|
52
|
+
private readonly keys;
|
|
53
|
+
private readonly options;
|
|
54
|
+
constructor(columnNames: readonly string[], options: DecodeOptions);
|
|
55
|
+
/** The object keys this mapper writes, in column order. */
|
|
56
|
+
get columnKeys(): readonly string[];
|
|
57
|
+
/** One row as an object. */
|
|
58
|
+
map<T>(cells: readonly ColumnValue[]): T;
|
|
59
|
+
/** Every row of a result set as objects. */
|
|
60
|
+
mapAll<T>(resultSet: CamusResultSet): T[];
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=result-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-set.d.ts","sourceRoot":"","sources":["../src/result-set.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAkB,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAE1B,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,qBAAa,cAAc;IACzB,gGAAgG;IAChG,MAAM,CAAC,QAAQ,CAAC,KAAK,iBAAqC;IAE1D,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAExC,QAAQ,CAAC,WAAW,EAAE,SAAS,UAAU,EAAE,CAAC;IAE5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;gBAG7C,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,QAAQ,EAAE,MAAM;IAQlB,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,oCAAoC;IACpC,IAAI,OAAO,IAAI,WAAW,EAAE,CAM3B;IAED,oBAAoB;IACpB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW;IAI9C,4BAA4B;IAC5B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE;CAInC;AAED;;;;;;GAMG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAW;IAEhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAE5B,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa;IAelE,2DAA2D;IAC3D,IAAI,UAAU,IAAI,SAAS,MAAM,EAAE,CAElC;IAED,4BAA4B;IAC5B,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,CAAC;IAUxC,4CAA4C;IAC5C,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,cAAc,GAAG,CAAC,EAAE;CAgB1C"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of CamusDB
|
|
3
|
+
*
|
|
4
|
+
* For the full copyright and license information, please view the LICENSE.txt
|
|
5
|
+
* file that was distributed with this source code.
|
|
6
|
+
*/
|
|
7
|
+
import { ColumnType, columnTypeName } from './column-type.js';
|
|
8
|
+
import { NULL_VALUE } from './column-value.js';
|
|
9
|
+
import { decodeValue } from './values/decode.js';
|
|
10
|
+
/**
|
|
11
|
+
* The rows of one query, held positionally.
|
|
12
|
+
*
|
|
13
|
+
* Cells live in a single flat array, row-major: cell `(row, column)` is at
|
|
14
|
+
* `row * columnCount + column`. The column names and declared types come from the response's
|
|
15
|
+
* authoritative schema, so the shape is known even when there are no rows — which is what lets a
|
|
16
|
+
* caller read `columns` before reading a row, and what makes an empty result still describe
|
|
17
|
+
* itself.
|
|
18
|
+
*/
|
|
19
|
+
export class CamusResultSet {
|
|
20
|
+
/** An empty result: no rows and no columns. Shared, so a count-only reply allocates nothing. */
|
|
21
|
+
static EMPTY = new CamusResultSet([], [], [], 0);
|
|
22
|
+
columnNames;
|
|
23
|
+
columnTypes;
|
|
24
|
+
rowCount;
|
|
25
|
+
cells;
|
|
26
|
+
constructor(columnNames, columnTypes, cells, rowCount) {
|
|
27
|
+
this.columnNames = columnNames;
|
|
28
|
+
this.columnTypes = columnTypes;
|
|
29
|
+
this.cells = cells;
|
|
30
|
+
this.rowCount = rowCount;
|
|
31
|
+
}
|
|
32
|
+
get columnCount() {
|
|
33
|
+
return this.columnNames.length;
|
|
34
|
+
}
|
|
35
|
+
/** The output columns, in order. */
|
|
36
|
+
get columns() {
|
|
37
|
+
return this.columnNames.map((name, index) => ({
|
|
38
|
+
name,
|
|
39
|
+
type: this.columnTypes[index] ?? ColumnType.Null,
|
|
40
|
+
typeName: columnTypeName(this.columnTypes[index] ?? ColumnType.Null),
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
/** One raw cell. */
|
|
44
|
+
cell(row, column) {
|
|
45
|
+
return this.cells[row * this.columnCount + column] ?? NULL_VALUE;
|
|
46
|
+
}
|
|
47
|
+
/** One row as raw cells. */
|
|
48
|
+
rawRow(row) {
|
|
49
|
+
const start = row * this.columnCount;
|
|
50
|
+
return this.cells.slice(start, start + this.columnCount);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Turns positional cells into a plain object, keyed by column name.
|
|
55
|
+
*
|
|
56
|
+
* A duplicate column name — which a join projection can produce — keeps the leftmost column, and
|
|
57
|
+
* the ones after it are reachable at `name_2`, `name_3`, and so on. Silently dropping a column
|
|
58
|
+
* would lose data the query asked for.
|
|
59
|
+
*/
|
|
60
|
+
export class RowMapper {
|
|
61
|
+
keys;
|
|
62
|
+
options;
|
|
63
|
+
constructor(columnNames, options) {
|
|
64
|
+
this.options = options;
|
|
65
|
+
this.keys = new Array(columnNames.length);
|
|
66
|
+
const used = new Map();
|
|
67
|
+
for (let i = 0; i < columnNames.length; i++) {
|
|
68
|
+
const name = columnNames[i] ?? `column_${String(i + 1)}`;
|
|
69
|
+
const seen = used.get(name) ?? 0;
|
|
70
|
+
used.set(name, seen + 1);
|
|
71
|
+
this.keys[i] = seen === 0 ? name : `${name}_${String(seen + 1)}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** The object keys this mapper writes, in column order. */
|
|
75
|
+
get columnKeys() {
|
|
76
|
+
return this.keys;
|
|
77
|
+
}
|
|
78
|
+
/** One row as an object. */
|
|
79
|
+
map(cells) {
|
|
80
|
+
const row = {};
|
|
81
|
+
for (let i = 0; i < this.keys.length; i++) {
|
|
82
|
+
row[this.keys[i]] = decodeValue(cells[i] ?? NULL_VALUE, this.options);
|
|
83
|
+
}
|
|
84
|
+
return row;
|
|
85
|
+
}
|
|
86
|
+
/** Every row of a result set as objects. */
|
|
87
|
+
mapAll(resultSet) {
|
|
88
|
+
const columnCount = resultSet.columnCount;
|
|
89
|
+
const rows = new Array(resultSet.rowCount);
|
|
90
|
+
for (let r = 0; r < resultSet.rowCount; r++) {
|
|
91
|
+
const row = {};
|
|
92
|
+
for (let c = 0; c < columnCount; c++) {
|
|
93
|
+
row[this.keys[c]] = decodeValue(resultSet.cell(r, c), this.options);
|
|
94
|
+
}
|
|
95
|
+
rows[r] = row;
|
|
96
|
+
}
|
|
97
|
+
return rows;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=result-set.js.map
|