@aws-blocks/bb-distributed-data 0.1.2 → 0.1.3
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 +3 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +7 -0
- package/dist/validation.test.js +27 -0
- package/package.json +1 -1
package/DESIGN.md
CHANGED
|
@@ -74,6 +74,7 @@ The core insight: PGlite supports everything DSQL doesn't. Without validation, c
|
|
|
74
74
|
| `CREATE TEMP TABLE` | Temporary tables |
|
|
75
75
|
| `SET TRANSACTION ISOLATION LEVEL` | Fixed Repeatable Read |
|
|
76
76
|
| `COLLATE` | C collation only |
|
|
77
|
+
| `CREATE INDEX ... ASC/DESC` | Sort direction on index keys (NULLS FIRST/LAST is allowed) |
|
|
77
78
|
|
|
78
79
|
### Transaction Tracking
|
|
79
80
|
|
package/README.md
CHANGED
|
@@ -108,6 +108,7 @@ DSQL is a subset of PostgreSQL. The local mock enforces these restrictions so co
|
|
|
108
108
|
| LISTEN / NOTIFY | AppSync Events, EventBridge, or polling |
|
|
109
109
|
| Extensions | Not available |
|
|
110
110
|
| ADD COLUMN with DEFAULT | Add column without default, handle nulls in app |
|
|
111
|
+
| Index key sort direction (`ASC`/`DESC`) | Omit it; enforce ordering with `ORDER BY` in queries (`NULLS FIRST/LAST` is supported) |
|
|
111
112
|
|
|
112
113
|
### Transaction Constraints
|
|
113
114
|
|
package/dist/e2e-mock.test.js
CHANGED
|
@@ -154,6 +154,9 @@ describe('DsqlMockEngine — CREATE INDEX ASYNC parity', () => {
|
|
|
154
154
|
it('still supports a plain CREATE INDEX (no ASYNC)', async () => {
|
|
155
155
|
await assert.doesNotReject(() => engine.withDdl(() => db.execute(sql `CREATE INDEX idx_users_plain ON users(id)`)));
|
|
156
156
|
});
|
|
157
|
+
it('rejects CREATE INDEX ASYNC with a DESC sort order on a key', async () => {
|
|
158
|
+
await assert.rejects(() => engine.withDdl(() => db.execute(sql `CREATE INDEX ASYNC idx_users_email_desc ON users (email DESC)`)), /sort order/i);
|
|
159
|
+
});
|
|
157
160
|
it('does not strip ASYNC outside of CREATE INDEX (column named "async")', async () => {
|
|
158
161
|
await engine.withDdl(() => db.execute(sql `CREATE TABLE jobs (id TEXT PRIMARY KEY, async BOOLEAN)`));
|
|
159
162
|
await db.execute(sql `INSERT INTO jobs (id, async) VALUES (${'j1'}, ${true})`);
|
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;AA6BD,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
|
@@ -80,6 +80,13 @@ const RULES = [
|
|
|
80
80
|
{ pattern: /\bCOLLATE\b/i, message: 'DSQL only supports C collation.', severity: 'error' },
|
|
81
81
|
{ pattern: /(?<!::)\bJSONB\b/i, message: 'DSQL does not support JSONB columns. Use JSON instead (JSONB is available as a query runtime cast via ::jsonb).', severity: 'error' },
|
|
82
82
|
{ pattern: /(@>|<@|\?\||\?&)/, message: 'JSONB operators lack GIN index acceleration in DSQL.', severity: 'warn' },
|
|
83
|
+
// DSQL rejects a sort direction (ASC/DESC) on index keys — it isn't in the
|
|
84
|
+
// CREATE INDEX ASYNC grammar (only `NULLS FIRST|LAST`, which IS supported, is).
|
|
85
|
+
// `[^;]*` keeps the match inside a single statement; ASC/DESC cannot otherwise
|
|
86
|
+
// appear in a CREATE INDEX. Caveat: stripLiteralsAndComments doesn't strip
|
|
87
|
+
// double-quoted identifiers, so a column literally named "desc"/"asc" would
|
|
88
|
+
// false-positive — niche, and shared with other single-keyword rules here.
|
|
89
|
+
{ pattern: /\bCREATE\s+(?:UNIQUE\s+)?INDEX\b[^;]*\b(?:ASC|DESC)\b/i, message: 'DSQL does not support sort order (ASC/DESC) on index keys. Remove it — ordering is enforced by ORDER BY in queries (NULLS FIRST/LAST is allowed). (DSQL: "specifying sort order not supported for index keys")', severity: 'error' },
|
|
83
90
|
];
|
|
84
91
|
/** Validate a SQL statement for DSQL compatibility. Throws on unsupported features. */
|
|
85
92
|
export function validateStatement(sql) {
|
package/dist/validation.test.js
CHANGED
|
@@ -352,3 +352,30 @@ describe('validateStatement — unsupported features after bind parameters', ()
|
|
|
352
352
|
assert.doesNotThrow(() => validateStatement("INSERT INTO audit (id, action) VALUES ($1, 'TRUNCATE')"));
|
|
353
353
|
});
|
|
354
354
|
});
|
|
355
|
+
describe('validateStatement — index key sort order', () => {
|
|
356
|
+
it('rejects DESC on an index key', () => {
|
|
357
|
+
assert.throws(() => validateStatement('CREATE INDEX idx ON persons (user_id, last_encounter_at DESC)'), /sort order/i);
|
|
358
|
+
});
|
|
359
|
+
it('rejects DESC on a CREATE INDEX ASYNC key', () => {
|
|
360
|
+
assert.throws(() => validateStatement('CREATE INDEX ASYNC idx_persons_user_recent ON persons (user_id, last_encounter_at DESC)'), /sort order/i);
|
|
361
|
+
});
|
|
362
|
+
it('rejects an explicit ASC on an index key', () => {
|
|
363
|
+
assert.throws(() => validateStatement('CREATE INDEX idx ON t (col ASC)'), /sort order/i);
|
|
364
|
+
});
|
|
365
|
+
it('allows NULLS FIRST / NULLS LAST on an index key (supported by DSQL)', () => {
|
|
366
|
+
assert.doesNotThrow(() => validateStatement('CREATE INDEX ASYNC idx ON t (col NULLS FIRST)'));
|
|
367
|
+
assert.doesNotThrow(() => validateStatement('CREATE INDEX ASYNC idx ON t (col NULLS LAST)'));
|
|
368
|
+
});
|
|
369
|
+
it('allows a plain CREATE INDEX without sort order', () => {
|
|
370
|
+
assert.doesNotThrow(() => validateStatement('CREATE INDEX idx ON persons (user_id, last_encounter_at)'));
|
|
371
|
+
});
|
|
372
|
+
it('allows a partial index whose WHERE mentions a column like "description"', () => {
|
|
373
|
+
assert.doesNotThrow(() => validateStatement('CREATE INDEX idx ON t (name) WHERE description IS NOT NULL'));
|
|
374
|
+
});
|
|
375
|
+
it('allows an expression index without sort order', () => {
|
|
376
|
+
assert.doesNotThrow(() => validateStatement('CREATE INDEX idx ON t ((lower(name)))'));
|
|
377
|
+
});
|
|
378
|
+
it('does not flag ORDER BY ... DESC in a SELECT (no false positive outside CREATE INDEX)', () => {
|
|
379
|
+
assert.doesNotThrow(() => validateStatement('SELECT * FROM persons ORDER BY last_encounter_at DESC'));
|
|
380
|
+
});
|
|
381
|
+
});
|