@aws-blocks/bb-distributed-data 0.1.3 → 0.1.5
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/DESIGN.md +1 -0
- package/README.md +1 -0
- package/dist/e2e-mock.test.js +4 -0
- package/dist/index.aws.d.ts.map +1 -1
- package/dist/index.aws.js +2 -1
- package/dist/index.cdk.d.ts +7 -0
- package/dist/index.cdk.d.ts.map +1 -1
- package/dist/index.cdk.js +10 -1
- package/dist/index.mock.d.ts.map +1 -1
- package/dist/index.mock.js +2 -1
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +56 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1 -0
- package/dist/validation.test.js +26 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/package.json +14 -4
package/DESIGN.md
CHANGED
|
@@ -75,6 +75,7 @@ The core insight: PGlite supports everything DSQL doesn't. Without validation, c
|
|
|
75
75
|
| `SET TRANSACTION ISOLATION LEVEL` | Fixed Repeatable Read |
|
|
76
76
|
| `COLLATE` | C collation only |
|
|
77
77
|
| `CREATE INDEX ... ASC/DESC` | Sort direction on index keys (NULLS FIRST/LAST is allowed) |
|
|
78
|
+
| `ALTER TABLE ... DROP [COLUMN]` | Not in DSQL's supported ALTER TABLE subset (`DROP CONSTRAINT` and `ALTER COLUMN ... DROP DEFAULT/NOT NULL/EXPRESSION/IDENTITY` are supported) |
|
|
78
79
|
|
|
79
80
|
### Transaction Tracking
|
|
80
81
|
|
package/README.md
CHANGED
|
@@ -109,6 +109,7 @@ DSQL is a subset of PostgreSQL. The local mock enforces these restrictions so co
|
|
|
109
109
|
| Extensions | Not available |
|
|
110
110
|
| ADD COLUMN with DEFAULT | Add column without default, handle nulls in app |
|
|
111
111
|
| Index key sort direction (`ASC`/`DESC`) | Omit it; enforce ordering with `ORDER BY` in queries (`NULLS FIRST/LAST` is supported) |
|
|
112
|
+
| `ALTER TABLE DROP [COLUMN]` | Leave the column in place and stop referencing it; or rebuild the table (create new → `INSERT INTO ... SELECT` → `DROP` → `RENAME TO`, one migration file per step) |
|
|
112
113
|
|
|
113
114
|
### Transaction Constraints
|
|
114
115
|
|
package/dist/e2e-mock.test.js
CHANGED
|
@@ -157,6 +157,10 @@ describe('DsqlMockEngine — CREATE INDEX ASYNC parity', () => {
|
|
|
157
157
|
it('rejects CREATE INDEX ASYNC with a DESC sort order on a key', async () => {
|
|
158
158
|
await assert.rejects(() => engine.withDdl(() => db.execute(sql `CREATE INDEX ASYNC idx_users_email_desc ON users (email DESC)`)), /sort order/i);
|
|
159
159
|
});
|
|
160
|
+
it('rejects ALTER TABLE DROP COLUMN', async () => {
|
|
161
|
+
await engine.withDdl(() => db.execute(sql `CREATE TABLE legacy (id TEXT PRIMARY KEY, obsolete TEXT)`));
|
|
162
|
+
await assert.rejects(() => engine.withDdl(() => db.execute(sql `ALTER TABLE legacy DROP COLUMN obsolete`)), /DROP COLUMN/i);
|
|
163
|
+
});
|
|
160
164
|
it('does not strip ASYNC outside of CREATE INDEX (column named "async")', async () => {
|
|
161
165
|
await engine.withDdl(() => db.execute(sql `CREATE TABLE jobs (id TEXT PRIMARY KEY, async BOOLEAN)`));
|
|
162
166
|
await db.execute(sql `INSERT INTO jobs (id, async) VALUES (${'j1'}, ${true})`);
|
package/dist/index.aws.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.aws.d.ts","sourceRoot":"","sources":["../src/index.aws.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAA0B,MAAM,kBAAkB,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAIxF,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.aws.d.ts","sourceRoot":"","sources":["../src/index.aws.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAA0B,MAAM,kBAAkB,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAIxF,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,OAAO,CAAC,KAAK,CAA6B;IAE1C,2FAA2F;IAC3F,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC;gBAEf,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,0BAA0B;IAQjF,OAAO,KAAK,IAAI,GAiBf;IAED,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IACvC,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAC/C,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAEvD;;;;;OAKG;IACG,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC;IAInG,gBAAgB;IAChB,SAAS;CACV;AAED,OAAO,EAAE,GAAG,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.aws.js
CHANGED
|
@@ -11,12 +11,13 @@ import { DsqlEngine } from './engines/dsql-engine.js';
|
|
|
11
11
|
import { transactionWithRetry } from './transaction.js';
|
|
12
12
|
import { ENV_SANITIZE, sanitizeDbRoleName } from './constants.js';
|
|
13
13
|
import { Logger } from '@aws-blocks/bb-logger';
|
|
14
|
+
import { BB_NAME, BB_VERSION } from './version.js';
|
|
14
15
|
export class DistributedDatabase extends Scope {
|
|
15
16
|
_base = null;
|
|
16
17
|
/** @internal Logger for internal operations. Defaults to error-level when not provided. */
|
|
17
18
|
log;
|
|
18
19
|
constructor(scope, id, _options) {
|
|
19
|
-
super(id, { parent: scope });
|
|
20
|
+
super(id, { parent: scope, bbName: BB_NAME, bbVersion: BB_VERSION });
|
|
20
21
|
this.log = _options?.logger ?? new Logger(this, 'logger', { level: 'error' });
|
|
21
22
|
const envName = this.fullId.replace(ENV_SANITIZE, '_');
|
|
22
23
|
const clusterEndpoint = process.env[`BLOCKS_${envName}_ENDPOINT`] ?? '';
|
package/dist/index.cdk.d.ts
CHANGED
|
@@ -8,6 +8,13 @@ import type { ScopeParent } from '@aws-blocks/core';
|
|
|
8
8
|
import type { DistributedDatabaseOptions } from './types.js';
|
|
9
9
|
export declare class DistributedDatabase extends Scope {
|
|
10
10
|
constructor(scope: ScopeParent, id: string, options?: DistributedDatabaseOptions);
|
|
11
|
+
/**
|
|
12
|
+
* Runtime-only. This is the CDK (synth) build: it defines infrastructure and
|
|
13
|
+
* has no engine — queries run in the app Lambda against the deployed cluster.
|
|
14
|
+
* `createKyselyAdapter()` no longer calls this eagerly, so reaching it means a
|
|
15
|
+
* query ran at synth time (e.g. at module scope).
|
|
16
|
+
*/
|
|
17
|
+
getEngine(): never;
|
|
11
18
|
}
|
|
12
19
|
export { sql, createKyselyAdapter } from '@aws-blocks/data-common';
|
|
13
20
|
export type { SqlQuery, Transaction } from '@aws-blocks/data-common';
|
package/dist/index.cdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cdk.d.ts","sourceRoot":"","sources":["../src/index.cdk.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"index.cdk.d.ts","sourceRoot":"","sources":["../src/index.cdk.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAoC,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQpD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAG7D,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,0BAA0B;IAyFhF;;;;;OAKG;IACH,SAAS,IAAI,KAAK;CAGnB;AAaD,OAAO,EAAE,GAAG,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.cdk.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Provisions Aurora DSQL cluster via CloudFormation.
|
|
6
6
|
* Optionally runs migrations via a CustomResource Lambda.
|
|
7
7
|
*/
|
|
8
|
-
import { Scope, DEFAULT_NODE_RUNTIME } from '@aws-blocks/core/cdk';
|
|
8
|
+
import { Scope, DEFAULT_NODE_RUNTIME, synthGuard } from '@aws-blocks/core/cdk';
|
|
9
9
|
import * as cdk from 'aws-cdk-lib';
|
|
10
10
|
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
11
11
|
import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
|
|
@@ -88,6 +88,15 @@ export class DistributedDatabase extends Scope {
|
|
|
88
88
|
// Ensure migrations run after cluster is created
|
|
89
89
|
migrationCR.node.addDependency(cluster);
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Runtime-only. This is the CDK (synth) build: it defines infrastructure and
|
|
93
|
+
* has no engine — queries run in the app Lambda against the deployed cluster.
|
|
94
|
+
* `createKyselyAdapter()` no longer calls this eagerly, so reaching it means a
|
|
95
|
+
* query ran at synth time (e.g. at module scope).
|
|
96
|
+
*/
|
|
97
|
+
getEngine() {
|
|
98
|
+
return synthGuard('DistributedDatabase', 'getEngine');
|
|
99
|
+
}
|
|
91
100
|
}
|
|
92
101
|
/** Hash all .sql files in a directory to detect changes. */
|
|
93
102
|
function hashMigrationsDir(dir) {
|
package/dist/index.mock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mock.d.ts","sourceRoot":"","sources":["../src/index.mock.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAA0B,MAAM,kBAAkB,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAIxF,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.mock.d.ts","sourceRoot":"","sources":["../src/index.mock.ts"],"names":[],"mappings":"AAGA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAA0B,MAAM,kBAAkB,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAIxF,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,aAAa,CAA8B;IAEnD,2FAA2F;IAC3F,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC;gBAEf,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,0BAA0B;YAelE,KAAK;IAEnB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IACvC,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAC/C,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAEvD;;;;;OAKG;IACG,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC;IAKnG,yDAAyD;IACzD,gBAAgB,IAAI,IAAI;IAExB,gBAAgB;IAChB,SAAS;CACV;AAED,OAAO,EAAE,GAAG,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.mock.js
CHANGED
|
@@ -10,6 +10,7 @@ import { DsqlMockEngine } from './engines/dsql-mock-engine.js';
|
|
|
10
10
|
import { runMigrations, loadMigrationsFromDir } from './migrations.js';
|
|
11
11
|
import { transactionWithRetry } from './transaction.js';
|
|
12
12
|
import { Logger } from '@aws-blocks/bb-logger';
|
|
13
|
+
import { BB_NAME, BB_VERSION } from './version.js';
|
|
13
14
|
export class DistributedDatabase extends Scope {
|
|
14
15
|
base;
|
|
15
16
|
mockEngine;
|
|
@@ -17,7 +18,7 @@ export class DistributedDatabase extends Scope {
|
|
|
17
18
|
/** @internal Logger for internal operations. Defaults to error-level when not provided. */
|
|
18
19
|
log;
|
|
19
20
|
constructor(scope, id, options) {
|
|
20
|
-
super(id, { parent: scope });
|
|
21
|
+
super(id, { parent: scope, bbName: BB_NAME, bbVersion: BB_VERSION });
|
|
21
22
|
this.log = options?.logger ?? new Logger(this, 'logger', { level: 'error' });
|
|
22
23
|
this.mockEngine = new DsqlMockEngine(`.bb-data/${this.fullId}`);
|
|
23
24
|
this.base = new DatabaseBase(this.mockEngine);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Telemetry-registration tests for DistributedDatabase.
|
|
5
|
+
*
|
|
6
|
+
* `Scope.getRegisteredBlocks()` only names a block whose `bbName` is in
|
|
7
|
+
* OFFICIAL_BB_NAMES, and that set is generated from the umbrella's
|
|
8
|
+
* `aws-blocks.vendorize` map. These tests pin the three coupled artifacts to
|
|
9
|
+
* each other: the block's generated BB_NAME, its vendorize entry, and the
|
|
10
|
+
* generated name set. A block that omits `bbMeta` still constructs fine and
|
|
11
|
+
* every other test still passes, so that gap is only visible here.
|
|
12
|
+
*
|
|
13
|
+
* The package ships a distinct mock implementation (the default entry does not
|
|
14
|
+
* re-export the AWS class), so both `index.aws.ts` and `index.mock.ts` carry
|
|
15
|
+
* the `super()` change. Registration happens in `super()`, identical for both;
|
|
16
|
+
* these tests exercise the AWS class because its constructor is side-effect
|
|
17
|
+
* free (the mock eagerly spins up PGlite on disk), keeping the suite fast and
|
|
18
|
+
* deterministic.
|
|
19
|
+
*/
|
|
20
|
+
import { test, describe, beforeEach } from 'node:test';
|
|
21
|
+
import assert from 'node:assert';
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
import { dirname, join } from 'node:path';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
import { Scope } from '@aws-blocks/core';
|
|
26
|
+
import { DistributedDatabase } from './index.aws.js';
|
|
27
|
+
import { BB_NAME, BB_VERSION } from './version.js';
|
|
28
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
let counter = 0;
|
|
30
|
+
function makeDb() {
|
|
31
|
+
const scope = new Scope(`distdata-telemetry-${++counter}`);
|
|
32
|
+
return new DistributedDatabase(scope, 'db');
|
|
33
|
+
}
|
|
34
|
+
describe('DistributedDatabase telemetry registration', () => {
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
Scope._resetRegistry();
|
|
37
|
+
});
|
|
38
|
+
test('BB_NAME is the name the vendorize map and OFFICIAL_BB_NAMES carry', () => {
|
|
39
|
+
assert.strictEqual(BB_NAME, 'DistributedDatabase');
|
|
40
|
+
});
|
|
41
|
+
test('BB_VERSION tracks the package version', () => {
|
|
42
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
43
|
+
assert.strictEqual(BB_VERSION, pkg.version);
|
|
44
|
+
});
|
|
45
|
+
test('an instance carries bbName and bbVersion', () => {
|
|
46
|
+
const db = makeDb();
|
|
47
|
+
assert.strictEqual(db.bbName, BB_NAME);
|
|
48
|
+
assert.strictEqual(db.bbVersion, BB_VERSION);
|
|
49
|
+
});
|
|
50
|
+
test('registers as an official block, so telemetry is allowed to name it', () => {
|
|
51
|
+
makeDb();
|
|
52
|
+
const { blocks, customBlocksCount } = Scope.getRegisteredBlocks();
|
|
53
|
+
assert.deepStrictEqual(blocks.filter(b => b.name === BB_NAME), [{ name: BB_NAME, version: BB_VERSION }]);
|
|
54
|
+
assert.strictEqual(customBlocksCount, 0, 'must not be filtered out as an unnamed custom block');
|
|
55
|
+
});
|
|
56
|
+
});
|
package/dist/validation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,eAAe,EAAuB,MAAM,yBAAyB,CAAC;AAU/E,mEAAmE;AACnE,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA6C5D;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,eAAe,EAAuB,MAAM,yBAAyB,CAAC;AAU/E,mEAAmE;AACnE,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA6C5D;AA8BD,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAenD;AAED,kDAAkD;AAClD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,CAKtE;AAID,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAK;IAErB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAalC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAUnC,KAAK,IAAI,IAAI;CACd;AAID,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAiB3E;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
package/dist/validation.js
CHANGED
|
@@ -73,6 +73,7 @@ const RULES = [
|
|
|
73
73
|
{ pattern: /\b(LISTEN|NOTIFY)\b/i, message: 'DSQL does not support LISTEN/NOTIFY.', severity: 'error' },
|
|
74
74
|
{ pattern: /\bCREATE\s+EXTENSION\b/i, message: 'DSQL does not support extensions.', severity: 'error' },
|
|
75
75
|
{ pattern: /\bALTER\s+TABLE\b[\s\S]*\bADD\s+COLUMN\b[\s\S]*\bDEFAULT\b/i, message: 'DSQL does not support ADD COLUMN with DEFAULT.', severity: 'error' },
|
|
76
|
+
{ pattern: /\bALTER\s+TABLE\b[^;]*\bDROP\s+(?:COLUMN\b|IF\s+EXISTS\b|(?!(?:DEFAULT|NOT|EXPRESSION|IDENTITY|CONSTRAINT)\b)[\w"])/i, message: 'DSQL does not support ALTER TABLE DROP COLUMN. Leave the column in place and stop referencing it, or rebuild the table (create a new table → INSERT INTO ... SELECT → DROP → RENAME TO). (DSQL: "unsupported ALTER TABLE DROP COLUMN statement")', severity: 'error' },
|
|
76
77
|
{ pattern: /\bALTER\s+DEFAULT\s+PRIVILEGES\b/i, message: 'DSQL does not support ALTER DEFAULT PRIVILEGES.', severity: 'error' },
|
|
77
78
|
{ pattern: /\b(CREATE\s+POLICY|ENABLE\s+ROW\s+LEVEL\s+SECURITY)\b/i, message: 'DSQL does not support Row Level Security.', severity: 'error' },
|
|
78
79
|
{ pattern: /\bCREATE\s+(TEMP|TEMPORARY)\s+TABLE\b/i, message: 'DSQL does not support temporary tables.', severity: 'error' },
|
package/dist/validation.test.js
CHANGED
|
@@ -45,12 +45,38 @@ describe('validateStatement', () => {
|
|
|
45
45
|
['ISOLATION LEVEL', 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'],
|
|
46
46
|
// DSQL only supports C collation — locale-aware sorting is not available
|
|
47
47
|
['COLLATE', 'SELECT * FROM t ORDER BY name COLLATE "en_US"'],
|
|
48
|
+
// DROP COLUMN is not in DSQL's supported ALTER TABLE subset — rebuild the table instead
|
|
49
|
+
['DROP COLUMN', 'ALTER TABLE t DROP COLUMN x'],
|
|
50
|
+
// Postgres allows omitting the COLUMN keyword — same DROP COLUMN action, same rejection
|
|
51
|
+
['DROP COLUMN shorthand', 'ALTER TABLE t DROP x'],
|
|
52
|
+
['DROP COLUMN IF EXISTS shorthand', 'ALTER TABLE t DROP IF EXISTS x'],
|
|
53
|
+
['DROP COLUMN quoted shorthand', 'ALTER TABLE t DROP "identity"'],
|
|
48
54
|
];
|
|
49
55
|
for (const [label, sql] of rejects) {
|
|
50
56
|
it(`rejects ${label}`, () => {
|
|
51
57
|
assert.throws(() => validateStatement(sql), { name: 'DsqlValidationError' });
|
|
52
58
|
});
|
|
53
59
|
}
|
|
60
|
+
it('allows supported ALTER TABLE forms that contain DROP', () => {
|
|
61
|
+
// Per the DSQL ALTER TABLE grammar, the ALTER COLUMN ... DROP actions and
|
|
62
|
+
// DROP CONSTRAINT are supported — must not be confused with the
|
|
63
|
+
// unsupported DROP [COLUMN].
|
|
64
|
+
// https://docs.aws.amazon.com/aurora-dsql/latest/userguide/alter-table-syntax-support.html
|
|
65
|
+
assert.doesNotThrow(() => validateStatement('ALTER TABLE t ALTER COLUMN c DROP IDENTITY'));
|
|
66
|
+
assert.doesNotThrow(() => validateStatement('ALTER TABLE t ALTER COLUMN c DROP DEFAULT'));
|
|
67
|
+
assert.doesNotThrow(() => validateStatement('ALTER TABLE t ALTER COLUMN c DROP NOT NULL'));
|
|
68
|
+
assert.doesNotThrow(() => validateStatement('ALTER TABLE t ALTER COLUMN c DROP EXPRESSION'));
|
|
69
|
+
assert.doesNotThrow(() => validateStatement('ALTER TABLE t DROP CONSTRAINT c'));
|
|
70
|
+
assert.doesNotThrow(() => validateStatement('ALTER TABLE t DROP CONSTRAINT IF EXISTS c CASCADE'));
|
|
71
|
+
assert.doesNotThrow(() => validateStatement('ALTER TABLE t RENAME TO t2'));
|
|
72
|
+
assert.doesNotThrow(() => validateStatement('DROP TABLE t'));
|
|
73
|
+
});
|
|
74
|
+
it('allows a supported ALTER TABLE followed by an unrelated statement in one batch', () => {
|
|
75
|
+
// The DROP COLUMN rule must not match across a statement boundary: the
|
|
76
|
+
// ALTER TABLE here is a supported DROP DEFAULT, and the DROP TABLE that
|
|
77
|
+
// follows the semicolon belongs to a different statement.
|
|
78
|
+
assert.doesNotThrow(() => validateStatement('ALTER TABLE t ALTER COLUMN c DROP DEFAULT; DROP TABLE archived'));
|
|
79
|
+
});
|
|
54
80
|
});
|
|
55
81
|
describe('classifyStatement', () => {
|
|
56
82
|
it('classifies DDL/DML/other', () => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,wBAAwB,CAAC;AAC7C,eAAO,MAAM,UAAU,UAAU,CAAC"}
|
package/dist/version.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws-blocks/bb-distributed-data",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/aws-devtools-labs/aws-blocks.git",
|
|
7
|
+
"directory": "packages/bb-distributed-data"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/aws-devtools-labs/aws-blocks/tree/main/packages/bb-distributed-data#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/aws-devtools-labs/aws-blocks/issues"
|
|
12
|
+
},
|
|
4
13
|
"author": "Amazon Web Services",
|
|
5
14
|
"license": "Apache-2.0",
|
|
6
15
|
"type": "module",
|
|
@@ -23,13 +32,14 @@
|
|
|
23
32
|
}
|
|
24
33
|
},
|
|
25
34
|
"scripts": {
|
|
35
|
+
"prebuild": "node ../../scripts/generate-version.mjs DistributedDatabase",
|
|
26
36
|
"build": "tsc --build",
|
|
27
37
|
"test": "node --test 'dist/**/*.test.js'"
|
|
28
38
|
},
|
|
29
39
|
"dependencies": {
|
|
30
|
-
"@aws-blocks/core": "^0.1.
|
|
31
|
-
"@aws-blocks/data-common": "^0.1.
|
|
32
|
-
"@aws-blocks/bb-logger": "^0.1.
|
|
40
|
+
"@aws-blocks/core": "^0.1.17",
|
|
41
|
+
"@aws-blocks/data-common": "^0.1.3",
|
|
42
|
+
"@aws-blocks/bb-logger": "^0.1.3",
|
|
33
43
|
"@aws-sdk/dsql-signer": "^3.700.0",
|
|
34
44
|
"@electric-sql/pglite": "^0.2.0",
|
|
35
45
|
"pg": "^8.13.0"
|