@kensio/yulin 1.21.28 → 1.21.30

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.
Files changed (68) hide show
  1. package/dist/sdk/wire/sim-sdk-wire-bedrock-action.d.ts +18 -0
  2. package/dist/sdk/wire/sim-sdk-wire-bedrock-action.js +71 -0
  3. package/dist/sdk/wire/sim-sdk-wire-bedrock-input.d.ts +11 -0
  4. package/dist/sdk/wire/sim-sdk-wire-bedrock-input.js +45 -0
  5. package/dist/sdk/wire/sim-sdk-wire-bedrock.d.ts +10 -0
  6. package/dist/sdk/wire/sim-sdk-wire-bedrock.js +47 -0
  7. package/dist/sdk/wire/sim-sdk-wire-call.d.ts +30 -0
  8. package/dist/sdk/wire/sim-sdk-wire-call.js +32 -0
  9. package/dist/sdk/wire/sim-sdk-wire-dispatcher.js +7 -9
  10. package/dist/sdk/wire/sim-sdk-wire-event-stream.d.ts +16 -0
  11. package/dist/sdk/wire/sim-sdk-wire-event-stream.js +79 -0
  12. package/dist/sdk/wire/sim-sdk-wire-unbridged.js +2 -2
  13. package/dist/service/athena/engine/sim-athena-array-shims.js +1 -1
  14. package/dist/service/athena/engine/sim-athena-binary-text.d.ts +2 -2
  15. package/dist/service/athena/engine/sim-athena-binary-text.js +2 -2
  16. package/dist/service/athena/engine/sim-athena-cast-rewrite.d.ts +30 -0
  17. package/dist/service/athena/engine/sim-athena-cast-rewrite.js +107 -0
  18. package/dist/service/athena/engine/sim-athena-cast-shims.d.ts +12 -0
  19. package/dist/service/athena/engine/sim-athena-cast-shims.js +29 -0
  20. package/dist/service/athena/engine/sim-athena-cast-text.d.ts +13 -0
  21. package/dist/service/athena/engine/sim-athena-cast-text.js +66 -0
  22. package/dist/service/athena/engine/sim-athena-comparison-shims.js +1 -2
  23. package/dist/service/athena/engine/sim-athena-date-arithmetic-shims.d.ts +4 -5
  24. package/dist/service/athena/engine/sim-athena-date-arithmetic-shims.js +6 -14
  25. package/dist/service/athena/engine/sim-athena-date-units.d.ts +1 -1
  26. package/dist/service/athena/engine/sim-athena-date-units.js +1 -1
  27. package/dist/service/athena/engine/sim-athena-engine-answer.d.ts +10 -5
  28. package/dist/service/athena/engine/sim-athena-engine-answer.js +4 -4
  29. package/dist/service/athena/engine/sim-athena-engine-run.d.ts +4 -0
  30. package/dist/service/athena/engine/sim-athena-engine-run.js +10 -2
  31. package/dist/service/athena/engine/sim-athena-regexp-shims.js +2 -2
  32. package/dist/service/athena/engine/sim-athena-shim-refusal.d.ts +17 -0
  33. package/dist/service/athena/engine/sim-athena-shim-refusal.js +22 -0
  34. package/dist/service/athena/engine/sim-athena-shim-registry.d.ts +5 -1
  35. package/dist/service/athena/engine/sim-athena-shim-registry.js +14 -2
  36. package/dist/service/athena/engine/sim-athena-shims.js +2 -0
  37. package/dist/service/athena/engine/sim-athena-sql-translation.d.ts +1 -23
  38. package/dist/service/athena/engine/sim-athena-sql-translation.js +8 -23
  39. package/dist/service/athena/engine/sim-athena-translated-sql.d.ts +29 -0
  40. package/dist/service/athena/engine/sim-athena-translated-sql.js +12 -0
  41. package/dist/service/athena/engine/sim-athena-turn-down.d.ts +7 -0
  42. package/dist/service/athena/engine/sim-athena-turn-down.js +11 -0
  43. package/dist/service/athena/result/sim-athena-query-answer.d.ts +2 -1
  44. package/dist/service/athena/result/sim-athena-query-answer.js +2 -1
  45. package/dist/service/athena/sim-athena-snapshot-table.fixture.d.ts +10 -0
  46. package/dist/service/athena/sim-athena-snapshot-table.fixture.js +39 -0
  47. package/dist/service/bedrock/command/authorize/sim-bedrock-authorizer.js +7 -3
  48. package/dist/service/lambda/function/code/vm/sdk/sim-sdk-lambda-vm-module-provider.d.ts +2 -2
  49. package/dist/service/lambda/function/code/vm/sdk/sim-sdk-lambda-vm-module-provider.js +5 -9
  50. package/dist/service/lambda/function/code/vm/sim-lambda-vm-context.d.ts +1 -1
  51. package/dist/service/lambda/function/code/vm/sim-lambda-vm-context.js +11 -22
  52. package/dist/service/lambda/function/code/vm/sim-lambda-vm-host-globals.d.ts +4 -0
  53. package/dist/service/lambda/function/code/vm/sim-lambda-vm-host-globals.js +87 -0
  54. package/dist/service/lambda/function/invoke/sim-lambda-outbound-clients.d.ts +3 -0
  55. package/dist/service/lambda/function/invoke/sim-lambda-outbound-clients.js +10 -0
  56. package/dist/service/lambda/function/outbound/sim-lambda-http2-exchanges.d.ts +32 -0
  57. package/dist/service/lambda/function/outbound/sim-lambda-http2-exchanges.js +39 -0
  58. package/dist/service/lambda/function/outbound/sim-lambda-http2-messages.d.ts +33 -0
  59. package/dist/service/lambda/function/outbound/sim-lambda-http2-messages.js +87 -0
  60. package/dist/service/lambda/function/outbound/sim-lambda-http2-module.d.ts +27 -0
  61. package/dist/service/lambda/function/outbound/sim-lambda-http2-module.js +53 -0
  62. package/dist/service/lambda/function/outbound/sim-lambda-http2-session.d.ts +31 -0
  63. package/dist/service/lambda/function/outbound/sim-lambda-http2-session.js +57 -0
  64. package/dist/service/lambda/function/outbound/sim-lambda-transport-module.d.ts +11 -0
  65. package/dist/service/lambda/function/outbound/sim-lambda-transport-module.js +24 -0
  66. package/docs/services/athena/README.md +29 -8
  67. package/docs/services/lambda/README.md +18 -8
  68. package/package.json +1 -1
@@ -0,0 +1,66 @@
1
+ // Both patterns below are anchored at each end with every quantifier bounded,
2
+ // so there is nothing in either to backtrack over.
3
+ // oxlint-disable security/detect-unsafe-regex
4
+ import { simAthenaInstant } from "./sim-athena-timestamp-text.js";
5
+ /**
6
+ * What Trino's cast from `varchar` to `DATE` reads, once the text is trimmed.
7
+ *
8
+ * A time of day is refused. `CAST('2026-08-15 10:00:00' AS DATE)` fails on
9
+ * Athena, and only a timestamp value loses its time to a cast.
10
+ */
11
+ const varcharDate = /^(\d{4})-(\d{1,2})-(\d{1,2})$/u;
12
+ /**
13
+ * What Trino's cast from `varchar` to `TIMESTAMP` reads.
14
+ *
15
+ * The time follows a space. A `T` between the date and the time fails the
16
+ * cast on Athena, and so does a zone, which belongs to `TIMESTAMP WITH TIME
17
+ * ZONE`.
18
+ */
19
+ const varcharTimestamp = /^(\d{4})-(\d{1,2})-(\d{1,2})(?: (\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d{1,12}))?)?)?$/u;
20
+ /**
21
+ * The instant one value names as the cast reads it, or nothing where the cast
22
+ * fails.
23
+ *
24
+ * Text is held to the formats Trino's cast from `varchar` takes. Any other
25
+ * source is a value some column or function already typed as a date or a
26
+ * timestamp, written as the ISO-8601 text the engine holds one as.
27
+ */
28
+ export function simAthenaCastInstant(text, type, fromText) {
29
+ if (!fromText) {
30
+ return simAthenaInstant(text);
31
+ }
32
+ const fields = type === "date"
33
+ ? varcharDate.exec(text.trim())
34
+ : varcharTimestamp.exec(text);
35
+ return fields === null ? undefined : instantOf(fields);
36
+ }
37
+ /** One instant rendered as Athena renders a value of the type. */
38
+ export function simAthenaCastRendered(instant, type) {
39
+ const iso = new Date(instant).toISOString();
40
+ return type === "date"
41
+ ? iso.slice(0, 10)
42
+ : iso.slice(0, 23).replace("T", " ");
43
+ }
44
+ /**
45
+ * The instant a matched value names, where every field is in range.
46
+ *
47
+ * `Date.UTC` rolls the 30th of February over into March, and Trino refuses
48
+ * it. Each field is checked against its calendar before anything is built.
49
+ * A fraction rounds to the millisecond, which is the precision Athena gives a
50
+ * `TIMESTAMP` with none written.
51
+ */
52
+ function instantOf(fields) {
53
+ const [year, month, day, hour, minute, second] = Array.from({ length: 6 }, (_, index) => Number(fields[index + 1] ?? 0));
54
+ const lastDay = new Date(Date.UTC(year, month, 0)).getUTCDate();
55
+ if (month < 1 ||
56
+ month > 12 ||
57
+ day < 1 ||
58
+ day > lastDay ||
59
+ hour > 23 ||
60
+ minute > 59 ||
61
+ second > 59) {
62
+ return undefined;
63
+ }
64
+ const milliseconds = Math.round(Number(`0.${fields[7] ?? "0"}`) * 1000);
65
+ return Date.UTC(year, month - 1, day, hour, minute, second, milliseconds);
66
+ }
@@ -57,8 +57,7 @@ function isNumeric(value) {
57
57
  * One argument as the text it orders by.
58
58
  *
59
59
  * A `varbinary` orders by its bytes in Trino, and nothing written out here
60
- * orders the same way. A call over one raises and the query falls back to its
61
- * declared result.
60
+ * orders the same way. A call over one raises and the query fails.
62
61
  */
63
62
  function comparableText(value) {
64
63
  if (value instanceof Uint8Array) {
@@ -2,10 +2,9 @@ import type { DatabaseSync } from "node:sqlite";
2
2
  /**
3
3
  * Trino's date arithmetic, over ISO-8601 text.
4
4
  *
5
- * Each of these raises rather than guessing where it cannot answer faithfully.
6
- * A unit outside the ones Trino names and a value that is no ISO-8601 timestamp
7
- * both land there, and the engine turns the query down and lets the declared
8
- * result answer. A shim answering a null instead would be a wrong answer
9
- * wearing the shape of a right one.
5
+ * Each of these raises where it cannot answer faithfully. A unit outside the
6
+ * ones Trino names and a value that is no ISO-8601 timestamp both land there,
7
+ * and the engine fails the query with the reason. A shim answering a null
8
+ * would be a wrong answer wearing the shape of a right one.
10
9
  */
11
10
  export declare function simAthenaInstallDateArithmeticShims(database: DatabaseSync): void;
@@ -6,11 +6,10 @@ import { simAthenaInstant, simAthenaRenderLike, } from "./sim-athena-timestamp-t
6
6
  /**
7
7
  * Trino's date arithmetic, over ISO-8601 text.
8
8
  *
9
- * Each of these raises rather than guessing where it cannot answer faithfully.
10
- * A unit outside the ones Trino names and a value that is no ISO-8601 timestamp
11
- * both land there, and the engine turns the query down and lets the declared
12
- * result answer. A shim answering a null instead would be a wrong answer
13
- * wearing the shape of a right one.
9
+ * Each of these raises where it cannot answer faithfully. A unit outside the
10
+ * ones Trino names and a value that is no ISO-8601 timestamp both land there,
11
+ * and the engine fails the query with the reason. A shim answering a null
12
+ * would be a wrong answer wearing the shape of a right one.
14
13
  */
15
14
  export function simAthenaInstallDateArithmeticShims(database) {
16
15
  simAthenaScalarShim(database, "date_add", (unit, value, timestamp) => {
@@ -47,13 +46,7 @@ function unitOf(value) {
47
46
  ? unit
48
47
  : raise(`${unit} is no date unit the engine reads`);
49
48
  }
50
- /**
51
- * Turn the query down.
52
- *
53
- * A shim that cannot answer faithfully raises, and the engine catches it and
54
- * lets the declared result answer. Answering a null instead would be a wrong
55
- * answer wearing the shape of a right one.
56
- */
49
+ /** Fail the query, saying why the shim could not answer. */
57
50
  function raise(reason) {
58
51
  throw new SimAthenaSetUpError(reason);
59
52
  }
@@ -63,8 +56,7 @@ function raise(reason) {
63
56
  * Trino answers with a timestamp carrying the zone. There is nowhere to put one
64
57
  * here, so the answer is the wall clock alone, with any `Z` the value arrived
65
58
  * with taken off. A `Z` left on would say UTC over a time that is no longer in
66
- * it. A zone nobody has heard of raises out of `Intl`, and the query falls
67
- * back.
59
+ * it. A zone nobody has heard of raises out of `Intl`, and the query fails.
68
60
  */
69
61
  function inZone(at, zone) {
70
62
  if (at === undefined || zone === undefined) {
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * A shim answering a unit it does not know would be answering wrongly, so the
5
5
  * ones here are the whole of what `date_add` and `date_diff` take. Anything
6
- * else raises, and the engine turns the query down.
6
+ * else raises, and the query fails.
7
7
  */
8
8
  export declare function isDateUnit(unit: string): boolean;
9
9
  /**
@@ -19,7 +19,7 @@ const calendarUnits = new Map([
19
19
  *
20
20
  * A shim answering a unit it does not know would be answering wrongly, so the
21
21
  * ones here are the whole of what `date_add` and `date_diff` take. Anything
22
- * else raises, and the engine turns the query down.
22
+ * else raises, and the query fails.
23
23
  */
24
24
  export function isDateUnit(unit) {
25
25
  return clockUnits.has(unit) || calendarUnits.has(unit);
@@ -10,7 +10,12 @@ export interface SimAthenaEngineAnswer {
10
10
  readonly result: SimAthenaResolvedResult | undefined;
11
11
  /** What the engine could not do, where it turned the query down. */
12
12
  readonly turnedDown: string | undefined;
13
- /** Why Athena refuses the statement, where the engine found it invalid. */
13
+ /**
14
+ * Why the query fails whether or not the engine is strict.
15
+ *
16
+ * That is a statement Athena refuses, or one the engine ran and could not
17
+ * evaluate.
18
+ */
14
19
  readonly rejected: string | undefined;
15
20
  }
16
21
  /** One answer the engine ran for real. */
@@ -18,11 +23,11 @@ export declare function simAthenaEngineAnswered(result: SimAthenaResolvedResult)
18
23
  /** One query the engine turned down, and why. */
19
24
  export declare function simAthenaEngineTurnedDown(turnedDown: string): SimAthenaEngineAnswer;
20
25
  /**
21
- * One statement Athena refuses, and why.
26
+ * One statement that fails whatever mode the engine is in, and why.
22
27
  *
23
- * The engine ran nothing. A query that reaches this fails whether or not the
24
- * engine is strict, since the alternative is a green test on SQL the service
25
- * rejects.
28
+ * Athena refusing the statement is one reason, and the alternative there is a
29
+ * green test on SQL the service rejects. A function shim refusing a value is
30
+ * the other, and the alternative there is a query losing every row in silence.
26
31
  */
27
32
  export declare function simAthenaEngineRejected(rejected: string): SimAthenaEngineAnswer;
28
33
  /** An engine nobody turned on, which has no opinion about the query. */
@@ -7,11 +7,11 @@ export function simAthenaEngineTurnedDown(turnedDown) {
7
7
  return { result: undefined, turnedDown, rejected: undefined };
8
8
  }
9
9
  /**
10
- * One statement Athena refuses, and why.
10
+ * One statement that fails whatever mode the engine is in, and why.
11
11
  *
12
- * The engine ran nothing. A query that reaches this fails whether or not the
13
- * engine is strict, since the alternative is a green test on SQL the service
14
- * rejects.
12
+ * Athena refusing the statement is one reason, and the alternative there is a
13
+ * green test on SQL the service rejects. A function shim refusing a value is
14
+ * the other, and the alternative there is a query losing every row in silence.
15
15
  */
16
16
  export function simAthenaEngineRejected(rejected) {
17
17
  return { result: undefined, turnedDown: undefined, rejected };
@@ -29,5 +29,9 @@ export interface SimAthenaEngineRun {
29
29
  *
30
30
  * Each of them carries a reason out, which a strict engine fails the query
31
31
  * with.
32
+ *
33
+ * A function shim refusing one of the statement's values is the exception. The
34
+ * engine ran the statement and could not evaluate it, and the query fails
35
+ * whether or not the engine is strict.
32
36
  */
33
37
  export declare function simAthenaEngineRun(run: SimAthenaEngineRun): Promise<SimAthenaEngineAnswer>;
@@ -1,6 +1,7 @@
1
- import { simAthenaEngineAnswered, simAthenaEngineTurnedDown, } from "./sim-athena-engine-answer.js";
2
- import { simAthenaRunFailure } from "./sim-athena-turn-down.js";
1
+ import { simAthenaEngineAnswered, simAthenaEngineRejected, simAthenaEngineTurnedDown, } from "./sim-athena-engine-answer.js";
2
+ import { simAthenaRunFailure, simAthenaUnevaluable, } from "./sim-athena-turn-down.js";
3
3
  import { simAthenaEngineResult } from "./sim-athena-engine-result.js";
4
+ import { SimAthenaShimRefusal } from "./sim-athena-shim-refusal.js";
4
5
  import { simAthenaSqliteDatabase } from "./sim-athena-sqlite-database.js";
5
6
  import { simAthenaLoadedTables } from "./sim-athena-loaded-tables.js";
6
7
  /**
@@ -15,6 +16,10 @@ import { simAthenaLoadedTables } from "./sim-athena-loaded-tables.js";
15
16
  *
16
17
  * Each of them carries a reason out, which a strict engine fails the query
17
18
  * with.
19
+ *
20
+ * A function shim refusing one of the statement's values is the exception. The
21
+ * engine ran the statement and could not evaluate it, and the query fails
22
+ * whether or not the engine is strict.
18
23
  */
19
24
  export async function simAthenaEngineRun(run) {
20
25
  try {
@@ -41,6 +46,9 @@ export async function simAthenaEngineRun(run) {
41
46
  }
42
47
  }
43
48
  catch (error) {
49
+ if (error instanceof SimAthenaShimRefusal) {
50
+ return simAthenaEngineRejected(simAthenaUnevaluable(error));
51
+ }
44
52
  return simAthenaEngineTurnedDown(simAthenaRunFailure(error));
45
53
  }
46
54
  }
@@ -28,8 +28,8 @@ function matches(value, pattern) {
28
28
  *
29
29
  * Trino counts the groups from one and calls the whole match zero, which is
30
30
  * what a regular expression counts them as anywhere. Trino also refuses a group
31
- * the pattern has not got, and raising here turns the query down rather than
32
- * letting a negative index quietly count back from the end.
31
+ * the pattern has not got, and raising here fails the query where a negative
32
+ * index would quietly count back from the end.
33
33
  */
34
34
  function extracted(value, pattern, group) {
35
35
  if (!Number.isSafeInteger(group) || group < 0) {
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A Trino function shim that could not answer for one value.
3
+ *
4
+ * Each shim raises where it cannot answer faithfully, such as a date function
5
+ * handed text that is no timestamp. SQLite hands the error back out of the
6
+ * statement unchanged, and this class is how the engine tells it apart from
7
+ * SQLite refusing the statement itself.
8
+ *
9
+ * The engine fails the query on one of these whether or not it is strict. The
10
+ * statement parsed and SQLite ran it, so falling back would answer a query the
11
+ * engine had taken on with rows a declaration wrote for some other purpose,
12
+ * often no rows at all.
13
+ */
14
+ export declare class SimAthenaShimRefusal extends Error {
15
+ readonly name = "SimAthenaShimRefusal";
16
+ constructor(described: string, cause: unknown);
17
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A Trino function shim that could not answer for one value.
3
+ *
4
+ * Each shim raises where it cannot answer faithfully, such as a date function
5
+ * handed text that is no timestamp. SQLite hands the error back out of the
6
+ * statement unchanged, and this class is how the engine tells it apart from
7
+ * SQLite refusing the statement itself.
8
+ *
9
+ * The engine fails the query on one of these whether or not it is strict. The
10
+ * statement parsed and SQLite ran it, so falling back would answer a query the
11
+ * engine had taken on with rows a declaration wrote for some other purpose,
12
+ * often no rows at all.
13
+ */
14
+ export class SimAthenaShimRefusal extends Error {
15
+ name = "SimAthenaShimRefusal";
16
+ constructor(described, cause) {
17
+ const reason = cause instanceof Error ? cause.message : String(cause);
18
+ super(`${described} could not answer for this statement's values. ${reason}`, {
19
+ cause,
20
+ });
21
+ }
22
+ }
@@ -7,8 +7,12 @@ export type SimAthenaScalarShim = (...values: SQLOutputValue[]) => SQLInputValue
7
7
  * Every shim takes any number of arguments, because SQLite checks the count
8
8
  * against the JavaScript function's own arity otherwise and a Trino function
9
9
  * with an optional argument would stop resolving.
10
+ *
11
+ * Anything the shim raises comes back out as a `SimAthenaShimRefusal` naming
12
+ * the function as a statement wrote it, which fails the query. `described`
13
+ * is that name where it differs from the one registered.
10
14
  */
11
- export declare function simAthenaScalarShim(database: DatabaseSync, name: string, implementation: SimAthenaScalarShim): void;
15
+ export declare function simAthenaScalarShim(database: DatabaseSync, name: string, implementation: SimAthenaScalarShim, described?: string): void;
12
16
  /**
13
17
  * Whether an optional argument was written as an explicit `NULL`.
14
18
  *
@@ -1,12 +1,24 @@
1
+ import { SimAthenaShimRefusal } from "./sim-athena-shim-refusal.js";
1
2
  /**
2
3
  * Register one Trino scalar function on this database.
3
4
  *
4
5
  * Every shim takes any number of arguments, because SQLite checks the count
5
6
  * against the JavaScript function's own arity otherwise and a Trino function
6
7
  * with an optional argument would stop resolving.
8
+ *
9
+ * Anything the shim raises comes back out as a `SimAthenaShimRefusal` naming
10
+ * the function as a statement wrote it, which fails the query. `described`
11
+ * is that name where it differs from the one registered.
7
12
  */
8
- export function simAthenaScalarShim(database, name, implementation) {
9
- database.function(name, { varargs: true, deterministic: true }, (...values) => withEmptyBytes(implementation(...values)));
13
+ export function simAthenaScalarShim(database, name, implementation, described = name) {
14
+ database.function(name, { varargs: true, deterministic: true }, (...values) => {
15
+ try {
16
+ return withEmptyBytes(implementation(...values));
17
+ }
18
+ catch (error) {
19
+ throw new SimAthenaShimRefusal(described, error);
20
+ }
21
+ });
10
22
  }
11
23
  /**
12
24
  * One answer, with an empty `varbinary` written so that SQLite keeps it.
@@ -1,6 +1,7 @@
1
1
  import { simAthenaInstallAggregateShims } from "./sim-athena-aggregate-shims.js";
2
2
  import { simAthenaInstallArrayShims } from "./sim-athena-array-shims.js";
3
3
  import { simAthenaInstallBinaryShims } from "./sim-athena-binary-shims.js";
4
+ import { simAthenaInstallCastShims } from "./sim-athena-cast-shims.js";
4
5
  import { simAthenaInstallClockShims } from "./sim-athena-clock-shims.js";
5
6
  import { simAthenaInstallComparisonShims } from "./sim-athena-comparison-shims.js";
6
7
  import { simAthenaInstallDateArithmeticShims } from "./sim-athena-date-arithmetic-shims.js";
@@ -22,6 +23,7 @@ export function simAthenaInstallShims(database, startedAt) {
22
23
  simAthenaInstallClockShims(database, startedAt);
23
24
  simAthenaInstallDateShims(database);
24
25
  simAthenaInstallDateArithmeticShims(database);
26
+ simAthenaInstallCastShims(database);
25
27
  simAthenaInstallJsonShims(database);
26
28
  simAthenaInstallJsonDocumentShims(database);
27
29
  simAthenaInstallArrayShims(database);
@@ -1,28 +1,6 @@
1
1
  import type { SimAthenaCatalogTable } from "../table/sim-athena-catalog-table.js";
2
2
  import type { SimAthenaSqlParser } from "./sim-athena-parser-module.js";
3
- /** One statement translated for SQLite, or why it was not. */
4
- export type SimAthenaTranslatedSql = {
5
- readonly sql: string;
6
- /**
7
- * The decimal places each result column was rounded to, by position.
8
- *
9
- * Read here because the syntax tree is the only place that knows, and
10
- * the tree is gone by the time the answer is rendered.
11
- */
12
- readonly scales: ReadonlyMap<number, number>;
13
- readonly turnedDown: undefined;
14
- readonly rejected: undefined;
15
- } | {
16
- readonly sql: undefined;
17
- readonly scales: undefined;
18
- readonly turnedDown: string;
19
- readonly rejected: undefined;
20
- } | {
21
- readonly sql: undefined;
22
- readonly scales: undefined;
23
- readonly turnedDown: undefined;
24
- readonly rejected: string;
25
- };
3
+ import { type SimAthenaTranslatedSql } from "./sim-athena-translated-sql.js";
26
4
  interface SimAthenaSqlTranslationRequest {
27
5
  readonly parser: SimAthenaSqlParser;
28
6
  readonly athenaSql: string;
@@ -1,7 +1,9 @@
1
1
  import { simAthenaSqlForParser, simAthenaSqlForSqlite, } from "./sim-athena-sql-rewrites.js";
2
2
  import { simAthenaUnparsedStatement, simAthenaUnrewrittenUnnest, simAthenaUnwrittenStatement, } from "./sim-athena-turn-down.js";
3
3
  import { simAthenaRejectedStatement } from "./sim-athena-rejected-statement.js";
4
+ import { simAthenaRewriteCasts } from "./sim-athena-cast-rewrite.js";
4
5
  import { simAthenaRoundScales } from "./sim-athena-round-scales.js";
6
+ import { simAthenaRejectedSql, simAthenaTranslated, simAthenaTurnedDownSql, } from "./sim-athena-translated-sql.js";
5
7
  import { simAthenaRewriteUnnest } from "./sim-athena-unnest-rewrite.js";
6
8
  /**
7
9
  * One Athena statement written back out for SQLite, or why it is not.
@@ -26,16 +28,11 @@ export function simAthenaSqliteSql(request) {
26
28
  ast = parser.astify(read.sql, { database: "athena" });
27
29
  }
28
30
  catch {
29
- return turnedDown(simAthenaUnparsedStatement);
31
+ return simAthenaTurnedDownSql(simAthenaUnparsedStatement);
30
32
  }
31
33
  const rejected = simAthenaRejectedStatement(ast);
32
34
  if (rejected !== undefined) {
33
- return {
34
- sql: undefined,
35
- scales: undefined,
36
- turnedDown: undefined,
37
- rejected,
38
- };
35
+ return simAthenaRejectedSql(rejected);
39
36
  }
40
37
  try {
41
38
  if (!simAthenaRewriteUnnest({
@@ -43,27 +40,15 @@ export function simAthenaSqliteSql(request) {
43
40
  ordinality: read.ordinality,
44
41
  tables: request.tables,
45
42
  })) {
46
- return turnedDown(simAthenaUnrewrittenUnnest);
43
+ return simAthenaTurnedDownSql(simAthenaUnrewrittenUnnest);
47
44
  }
45
+ simAthenaRewriteCasts(ast, request.tables);
48
46
  // Read before the tree is written back out, since the rewrites above can
49
47
  // move a select item and the scale travels by position.
50
48
  const scales = simAthenaRoundScales(ast);
51
- return {
52
- sql: simAthenaSqlForSqlite(parser.sqlify(ast, { database: "sqlite" })),
53
- scales,
54
- turnedDown: undefined,
55
- rejected: undefined,
56
- };
49
+ return simAthenaTranslated(simAthenaSqlForSqlite(parser.sqlify(ast, { database: "sqlite" })), scales);
57
50
  }
58
51
  catch {
59
- return turnedDown(simAthenaUnwrittenStatement);
52
+ return simAthenaTurnedDownSql(simAthenaUnwrittenStatement);
60
53
  }
61
54
  }
62
- function turnedDown(reason) {
63
- return {
64
- sql: undefined,
65
- scales: undefined,
66
- turnedDown: reason,
67
- rejected: undefined,
68
- };
69
- }
@@ -0,0 +1,29 @@
1
+ /** One statement translated for SQLite, or why it was not. */
2
+ export type SimAthenaTranslatedSql = {
3
+ readonly sql: string;
4
+ /**
5
+ * The decimal places each result column was rounded to, by position.
6
+ *
7
+ * Read here because the syntax tree is the only place that knows, and
8
+ * the tree is gone by the time the answer is rendered.
9
+ */
10
+ readonly scales: ReadonlyMap<number, number>;
11
+ readonly turnedDown: undefined;
12
+ readonly rejected: undefined;
13
+ } | {
14
+ readonly sql: undefined;
15
+ readonly scales: undefined;
16
+ readonly turnedDown: string;
17
+ readonly rejected: undefined;
18
+ } | {
19
+ readonly sql: undefined;
20
+ readonly scales: undefined;
21
+ readonly turnedDown: undefined;
22
+ readonly rejected: string;
23
+ };
24
+ /** One statement written out for SQLite, with the scales read off its tree. */
25
+ export declare function simAthenaTranslated(sql: string, scales: ReadonlyMap<number, number>): SimAthenaTranslatedSql;
26
+ /** One statement the engine turned down, and why. */
27
+ export declare function simAthenaTurnedDownSql(turnedDown: string): SimAthenaTranslatedSql;
28
+ /** One statement Athena refuses, and why. */
29
+ export declare function simAthenaRejectedSql(rejected: string): SimAthenaTranslatedSql;
@@ -0,0 +1,12 @@
1
+ /** One statement written out for SQLite, with the scales read off its tree. */
2
+ export function simAthenaTranslated(sql, scales) {
3
+ return { sql, scales, turnedDown: undefined, rejected: undefined };
4
+ }
5
+ /** One statement the engine turned down, and why. */
6
+ export function simAthenaTurnedDownSql(turnedDown) {
7
+ return { sql: undefined, scales: undefined, turnedDown, rejected: undefined };
8
+ }
9
+ /** One statement Athena refuses, and why. */
10
+ export function simAthenaRejectedSql(rejected) {
11
+ return { sql: undefined, scales: undefined, turnedDown: undefined, rejected };
12
+ }
@@ -14,6 +14,13 @@ export declare const simAthenaUnrewrittenUnnest = "The simulated Athena query en
14
14
  export declare const simAthenaUnwrittenStatement = "The simulated Athena query engine cannot write this statement back out for SQLite.";
15
15
  /** Whatever went wrong while the tables were loaded or the statement ran. */
16
16
  export declare function simAthenaRunFailure(error: unknown): string;
17
+ /**
18
+ * A function shim that could not answer for one of the statement's values.
19
+ *
20
+ * This fails the query whether or not the engine is strict, so the reason
21
+ * points at the one declaration that still answers it.
22
+ */
23
+ export declare function simAthenaUnevaluable(refusal: Error): string;
17
24
  /**
18
25
  * One table the engine has no reader for.
19
26
  *
@@ -21,6 +21,17 @@ export function simAthenaRunFailure(error) {
21
21
  const message = error instanceof Error ? error.message : String(error);
22
22
  return `${engine} could not answer this statement. ${message}`;
23
23
  }
24
+ /**
25
+ * A function shim that could not answer for one of the statement's values.
26
+ *
27
+ * This fails the query whether or not the engine is strict, so the reason
28
+ * points at the one declaration that still answers it.
29
+ */
30
+ export function simAthenaUnevaluable(refusal) {
31
+ return (`${engine} cannot evaluate this statement. ${refusal.message} ` +
32
+ `Declare what this exact query answers with through results() to answer ` +
33
+ `it without the engine.`);
34
+ }
24
35
  /**
25
36
  * One table the engine has no reader for.
26
37
  *
@@ -51,7 +51,8 @@ interface SimAthenaQueryAnswerRequest {
51
51
  *
52
52
  * A statement Athena refuses fails whichever mode the engine is in. That is
53
53
  * SQL the service would never have run, and falling back would leave the query
54
- * green on it.
54
+ * green on it. So does a statement the engine ran and could not evaluate,
55
+ * where falling back to the default would answer with no rows at all.
55
56
  */
56
57
  export declare function simAthenaQueryAnswer(request: SimAthenaQueryAnswerRequest): Promise<SimAthenaQueryAnswer>;
57
58
  export {};
@@ -18,7 +18,8 @@ import { simAthenaStrictRefusal } from "../engine/sim-athena-turn-down.js";
18
18
  *
19
19
  * A statement Athena refuses fails whichever mode the engine is in. That is
20
20
  * SQL the service would never have run, and falling back would leave the query
21
- * green on it.
21
+ * green on it. So does a statement the engine ran and could not evaluate,
22
+ * where falling back to the default would answer with no rows at all.
22
23
  */
23
24
  export async function simAthenaQueryAnswer(request) {
24
25
  const forQuery = request.results.declaredForQuery(request.queryString);
@@ -0,0 +1,10 @@
1
+ import { type SimAthenaEngineSimulation } from "./sim-athena-engine.fixture.js";
2
+ /**
3
+ * A table of snapshots partitioned by a string `day`, with the engine on and
4
+ * a default declaration that a fallback would answer with.
5
+ *
6
+ * `taken_at` is a Glue `timestamp` written as ISO-8601 with a `T` and a `Z`.
7
+ * `noted_at` is a `string` holding a timestamp the way Trino's cast from text
8
+ * reads one.
9
+ */
10
+ export declare function aSnapshotSimulation(): Promise<SimAthenaEngineSimulation>;
@@ -0,0 +1,39 @@
1
+ import { aCatalogTable, anEngineSimulation, aSeededJson, } from "./sim-athena-engine.fixture.js";
2
+ /**
3
+ * A table of snapshots partitioned by a string `day`, with the engine on and
4
+ * a default declaration that a fallback would answer with.
5
+ *
6
+ * `taken_at` is a Glue `timestamp` written as ISO-8601 with a `T` and a `Z`.
7
+ * `noted_at` is a `string` holding a timestamp the way Trino's cast from text
8
+ * reads one.
9
+ */
10
+ export async function aSnapshotSimulation() {
11
+ const simulation = await anEngineSimulation();
12
+ aCatalogTable(simulation.simAws, {
13
+ name: "snapshots",
14
+ columns: [
15
+ { Name: "sku", Type: "string" },
16
+ { Name: "taken_at", Type: "timestamp" },
17
+ { Name: "noted_at", Type: "string" },
18
+ ],
19
+ partitionKeys: [{ Name: "day", Type: "string" }],
20
+ });
21
+ await aSeededJson(simulation.simAws, "snapshots/day=2026-08-15/part-0.json", [
22
+ {
23
+ sku: "bolt",
24
+ taken_at: "2026-08-15T23:30:00Z",
25
+ noted_at: "2026-08-15 10:00:00",
26
+ },
27
+ {
28
+ sku: "nut",
29
+ taken_at: "2026-08-14T08:00:00Z",
30
+ noted_at: "2026-08-14 09:15:00.5",
31
+ },
32
+ ]);
33
+ await simulation.simAws.athena().engine().enable();
34
+ simulation.simAws
35
+ .athena()
36
+ .results()
37
+ .byDefault({ columns: ["fallback"], rows: [["declared"]] });
38
+ return simulation;
39
+ }
@@ -24,9 +24,13 @@ export class SimBedrockAuthorizer {
24
24
  caller: options.caller,
25
25
  });
26
26
  if (decision.isDenied) {
27
- throw new SimBedrockAccessDeniedException(`User: ${this.callerIdentifier.format(decision.caller.principal)} is ` +
28
- `not authorized to perform: ${action} on resource: ${resource} ` +
29
- `because no identity-based policy allows the ${action} action`);
27
+ // A service control policy denial names the policy, as other services'
28
+ // denials do.
29
+ const reason = decision.denialReason ??
30
+ `because no identity-based policy allows the ${action} action`;
31
+ const caller = this.callerIdentifier.format(decision.caller.principal);
32
+ throw new SimBedrockAccessDeniedException(`User: ${caller} is not authorized to perform: ${action} on ` +
33
+ `resource: ${resource} ${reason}`);
30
34
  }
31
35
  return decision.caller;
32
36
  }
@@ -42,8 +42,8 @@ export declare class SimSdkLambdaVmModuleProvider implements SimLambdaVmSdkModul
42
42
  private readonly providedModules;
43
43
  constructor(properties: SimSdkLambdaVmModuleProviderProperties);
44
44
  /**
45
- * Provide an intercepted AWS SDK package or HTTP transport module, or
46
- * undefined for other specifiers.
45
+ * Provide an intercepted AWS SDK package or HTTP or HTTP/2 transport
46
+ * module, or undefined for other specifiers.
47
47
  */
48
48
  provideModule(specifier: string): unknown;
49
49
  /**