couchset 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -1
- package/dist/database.d.ts +6 -0
- package/dist/database.js +51 -2
- package/dist/database.js.map +1 -1
- package/dist/model/field-path.d.ts +8 -0
- package/dist/model/field-path.js +70 -0
- package/dist/model/field-path.js.map +1 -0
- package/dist/model/include.d.ts +36 -3
- package/dist/model/include.js +155 -49
- package/dist/model/include.js.map +1 -1
- package/dist/model/index.d.ts +4 -1
- package/dist/model/index.js +8 -1
- package/dist/model/index.js.map +1 -1
- package/dist/model/read-helpers.d.ts +6 -2
- package/dist/model/read-helpers.js +96 -23
- package/dist/model/read-helpers.js.map +1 -1
- package/dist/model/read-types.d.ts +51 -0
- package/dist/model/read-types.js +3 -0
- package/dist/model/read-types.js.map +1 -0
- package/dist/model/safe-query.d.ts +3 -0
- package/dist/model/safe-query.js +22 -2
- package/dist/model/safe-query.js.map +1 -1
- package/dist/next.d.ts +12 -2
- package/dist/next.js +3 -1
- package/dist/next.js.map +1 -1
- package/dist/next.types.js +149 -1
- package/dist/next.types.js.map +1 -1
- package/dist/pagination/pagination.js +3 -1
- package/dist/pagination/pagination.js.map +1 -1
- package/dist/pagination/types.d.ts +2 -0
- package/dist/pagination/types.js.map +1 -1
- package/dist/search/customQuery.d.ts +2 -0
- package/dist/search/customQuery.js +4 -1
- package/dist/search/customQuery.js.map +1 -1
- package/docs/beta-migration.md +1 -1
- package/docs/document-modeling.md +5 -1
- package/docs/joins-and-consistency.md +266 -0
- package/docs/next-primitives.md +4 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ The additive client-owned primitives—typed definitions, explicit provisioning,
|
|
|
20
20
|
- [Connection Lifecycle](#connection-lifecycle)
|
|
21
21
|
- [Models](#models)
|
|
22
22
|
- [Reads](#reads)
|
|
23
|
+
- [Typed Joins and Read Consistency](#typed-joins-and-read-consistency)
|
|
23
24
|
- [Document Modeling](./docs/document-modeling.md)
|
|
24
25
|
- [Writes](#writes)
|
|
25
26
|
- [Queries](#queries)
|
|
@@ -233,7 +234,15 @@ await startCouchbase();
|
|
|
233
234
|
await startCouchbaseServerless();
|
|
234
235
|
```
|
|
235
236
|
|
|
236
|
-
The starters
|
|
237
|
+
The starters accept one PostgreSQL-style `DB_URL` in place of the four connection settings. It takes precedence over `COUCHBASE_URL`, `COUCHBASE_BUCKET`, `COUCHBASE_USERNAME`, and `COUCHBASE_PASSWORD`; explicit `startCouchbase({...})` options still take precedence over either environment form.
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
DB_URL=couchbase://user:password@localhost/bucket
|
|
241
|
+
DB_URL=couchbase://user:password@localhost:11210/bucket
|
|
242
|
+
DB_URL=couchbases://user:password@cb.example.com/bucket
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Use `couchbases://` for TLS. Percent-encode reserved characters in usernames, passwords, and bucket names (for example, `p%40ss` for `p@ss`). `COUCHBASE_PROXY` remains available as a separate optional setting.
|
|
237
246
|
|
|
238
247
|
## Models
|
|
239
248
|
|
|
@@ -313,6 +322,89 @@ await users.onlyDeleted().findMany<User>();
|
|
|
313
322
|
await users.withoutDefaultWhere().findMany<User>();
|
|
314
323
|
```
|
|
315
324
|
|
|
325
|
+
## Typed Joins and Read Consistency
|
|
326
|
+
|
|
327
|
+
Client-bound models infer root and related fields. Using the client-owned `db`
|
|
328
|
+
above, join profiles to battles by arbitrary fields:
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
import {dateCodec, defineModel, joinField} from 'couchset/next';
|
|
332
|
+
import {QueryScanConsistency} from 'couchbase';
|
|
333
|
+
|
|
334
|
+
const battles = db.model(defineModel<{
|
|
335
|
+
createdByUserId: string;
|
|
336
|
+
startsAt: Date;
|
|
337
|
+
}>({name: 'Battle', scope: 'app', collection: 'battles', codecs: {startsAt: dateCodec}}));
|
|
338
|
+
|
|
339
|
+
const profiles = db.model(defineModel<{
|
|
340
|
+
ownerUserId: string;
|
|
341
|
+
displayName: string;
|
|
342
|
+
birthday: Date;
|
|
343
|
+
}>({name: 'Profile', scope: 'app', collection: 'profiles', codecs: {birthday: dateCodec}}));
|
|
344
|
+
|
|
345
|
+
const joined = await battles.page({
|
|
346
|
+
sourceAlias: 'battle',
|
|
347
|
+
include: [{
|
|
348
|
+
as: 'creator',
|
|
349
|
+
model: profiles,
|
|
350
|
+
type: 'leftJoin',
|
|
351
|
+
on: {
|
|
352
|
+
left: joinField('creator.ownerUserId'),
|
|
353
|
+
op: '$eq',
|
|
354
|
+
right: joinField('battle.createdByUserId'),
|
|
355
|
+
},
|
|
356
|
+
}],
|
|
357
|
+
limit: 20,
|
|
358
|
+
queryOptions: {scanConsistency: QueryScanConsistency.RequestPlus},
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
joined.items[0]?.startsAt; // Date | undefined
|
|
362
|
+
joined.items[0]?.creator?.birthday; // Date | undefined; related codec applied
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Provision the collections and appropriate indexes explicitly before querying.
|
|
366
|
+
`joinField()` denotes a field reference; an ordinary string is a bound value.
|
|
367
|
+
Use `$and` / `$or` to combine predicates. Existing `key` / `keys` includes still
|
|
368
|
+
use `ON KEYS`.
|
|
369
|
+
|
|
370
|
+
Use NEST for arrays, and select just the fields needed:
|
|
371
|
+
|
|
372
|
+
```ts
|
|
373
|
+
const summaries = await battles.findMany({
|
|
374
|
+
select: ['startsAt'],
|
|
375
|
+
include: [{
|
|
376
|
+
as: 'creators',
|
|
377
|
+
model: profiles,
|
|
378
|
+
type: 'leftNest',
|
|
379
|
+
on: {left: joinField('creators.ownerUserId'), op: '$eq', right: joinField('doc.createdByUserId')},
|
|
380
|
+
select: ['displayName', 'birthday'],
|
|
381
|
+
}],
|
|
382
|
+
});
|
|
383
|
+
// {startsAt: Date; creators: {displayName: string; birthday: Date}[]}[]
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
LEFT JOIN may omit its related property; LEFT NEST returns `[]` when unmatched.
|
|
387
|
+
JOIN preserves one row per match, including repeated root IDs. Choose an alias
|
|
388
|
+
that does not overwrite a root field. NEST does not promise source-key ordering.
|
|
389
|
+
|
|
390
|
+
For read-your-writes, pass tokens from successful SDK mutations:
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
import {MutationState, MutationToken} from 'couchbase';
|
|
394
|
+
|
|
395
|
+
async function readAfterWrites(tokens: MutationToken[]) {
|
|
396
|
+
return battles.findMany({
|
|
397
|
+
queryOptions: {consistentWith: new MutationState(...tokens)},
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
// Call with SDK mutationResult.token values, not whole mutation results.
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
`request_plus` and `consistentWith` are alternatives; neither is a multi-document
|
|
404
|
+
transaction. Defaults are unchanged when no consistency option is supplied.
|
|
405
|
+
See [joined reads and consistency](./docs/joins-and-consistency.md) for predicates,
|
|
406
|
+
projection limits, codecs, compatibility changes, and live validation results.
|
|
407
|
+
|
|
316
408
|
## Writes
|
|
317
409
|
|
|
318
410
|
```ts
|
package/dist/database.d.ts
CHANGED
|
@@ -3,6 +3,12 @@ export type CouchbaseStarterLogger = ((...args: any[]) => void) | false;
|
|
|
3
3
|
export interface StartCouchbaseOptions extends Partial<CouchsetArgs> {
|
|
4
4
|
logger?: CouchbaseStarterLogger;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Convert a PostgreSQL-style DB_URL into Couchbase SDK connection settings.
|
|
8
|
+
* The bucket lives in the URL path; it is not part of Couchbase's connection
|
|
9
|
+
* string, which contains only the scheme, host, optional port, and options.
|
|
10
|
+
*/
|
|
11
|
+
export declare const parseDatabaseUrl: (value: string) => Pick<CouchsetArgs, "bucketName" | "connectionString" | "password" | "username">;
|
|
6
12
|
export declare const getConnectionOptions: (overrides?: Partial<CouchsetArgs>) => CouchsetArgs;
|
|
7
13
|
export declare const connectionOptions: CouchsetArgs;
|
|
8
14
|
export declare const startCouchbase: (options?: StartCouchbaseOptions) => Promise<boolean>;
|
package/dist/database.js
CHANGED
|
@@ -86,13 +86,61 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
86
86
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
87
87
|
};
|
|
88
88
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
89
|
-
exports.startCouchbaseServerless = exports.startCouchbase = exports.connectionOptions = exports.getConnectionOptions = void 0;
|
|
89
|
+
exports.startCouchbaseServerless = exports.startCouchbase = exports.connectionOptions = exports.getConnectionOptions = exports.parseDatabaseUrl = void 0;
|
|
90
90
|
var connection_1 = __importDefault(require("./connection"));
|
|
91
91
|
var envValue = function (key, fallback) {
|
|
92
92
|
if (fallback === void 0) { fallback = ''; }
|
|
93
93
|
var value = typeof process !== 'undefined' && process.env ? process.env[key] : undefined;
|
|
94
94
|
return value === undefined ? fallback : value;
|
|
95
95
|
};
|
|
96
|
+
var databaseUrlError = function (reason) {
|
|
97
|
+
return new Error("DB_URL must use couchbase:// or couchbases://user:password@host/bucket: ".concat(reason));
|
|
98
|
+
};
|
|
99
|
+
var decodeDatabaseUrlComponent = function (value, label) {
|
|
100
|
+
try {
|
|
101
|
+
return decodeURIComponent(value);
|
|
102
|
+
}
|
|
103
|
+
catch (_error) {
|
|
104
|
+
throw databaseUrlError("".concat(label, " contains invalid percent-encoding"));
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Convert a PostgreSQL-style DB_URL into Couchbase SDK connection settings.
|
|
109
|
+
* The bucket lives in the URL path; it is not part of Couchbase's connection
|
|
110
|
+
* string, which contains only the scheme, host, optional port, and options.
|
|
111
|
+
*/
|
|
112
|
+
var parseDatabaseUrl = function (value) {
|
|
113
|
+
var url;
|
|
114
|
+
try {
|
|
115
|
+
url = new URL(value);
|
|
116
|
+
}
|
|
117
|
+
catch (_error) {
|
|
118
|
+
throw databaseUrlError('the value is not a valid URL');
|
|
119
|
+
}
|
|
120
|
+
if (url.protocol !== 'couchbase:' && url.protocol !== 'couchbases:') {
|
|
121
|
+
throw databaseUrlError("unsupported protocol ".concat(url.protocol || '(missing)'));
|
|
122
|
+
}
|
|
123
|
+
if (!url.hostname) {
|
|
124
|
+
throw databaseUrlError('a host is required');
|
|
125
|
+
}
|
|
126
|
+
if (!url.username || !url.password) {
|
|
127
|
+
throw databaseUrlError('a username and password are required');
|
|
128
|
+
}
|
|
129
|
+
if (url.hash) {
|
|
130
|
+
throw databaseUrlError('fragments are not supported');
|
|
131
|
+
}
|
|
132
|
+
var bucketName = decodeDatabaseUrlComponent(url.pathname.replace(/^\//, ''), 'the bucket name');
|
|
133
|
+
if (!bucketName || bucketName.indexOf('/') !== -1) {
|
|
134
|
+
throw databaseUrlError('the path must contain exactly one bucket name');
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
bucketName: bucketName,
|
|
138
|
+
connectionString: "".concat(url.protocol, "//").concat(url.host).concat(url.search),
|
|
139
|
+
password: decodeDatabaseUrlComponent(url.password, 'the password'),
|
|
140
|
+
username: decodeDatabaseUrlComponent(url.username, 'the username'),
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
exports.parseDatabaseUrl = parseDatabaseUrl;
|
|
96
144
|
var maskPassword = function (password) {
|
|
97
145
|
return password ? 'xxxxxx' : 'empty';
|
|
98
146
|
};
|
|
@@ -104,6 +152,7 @@ var splitStartOptions = function (options) {
|
|
|
104
152
|
var getConnectionOptions = function (overrides) {
|
|
105
153
|
if (overrides === void 0) { overrides = {}; }
|
|
106
154
|
var proxy = envValue('COUCHBASE_PROXY');
|
|
155
|
+
var databaseUrl = envValue('DB_URL');
|
|
107
156
|
var options = {
|
|
108
157
|
bucketName: envValue('COUCHBASE_BUCKET', 'dev'),
|
|
109
158
|
connectionString: envValue('COUCHBASE_URL', 'couchbase://localhost'),
|
|
@@ -113,7 +162,7 @@ var getConnectionOptions = function (overrides) {
|
|
|
113
162
|
if (proxy) {
|
|
114
163
|
options.proxy = proxy;
|
|
115
164
|
}
|
|
116
|
-
return __assign(__assign({}, options), overrides);
|
|
165
|
+
return __assign(__assign(__assign({}, options), (databaseUrl ? (0, exports.parseDatabaseUrl)(databaseUrl) : {})), overrides);
|
|
117
166
|
};
|
|
118
167
|
exports.getConnectionOptions = getConnectionOptions;
|
|
119
168
|
exports.connectionOptions = (0, exports.getConnectionOptions)();
|
package/dist/database.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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","sourcesContent":["import CouchbaseConnection, {CouchsetArgs} from './connection';\n\nexport type CouchbaseStarterLogger = ((...args: any[]) => void) | false;\n\nexport interface StartCouchbaseOptions extends Partial<CouchsetArgs> {\n logger?: CouchbaseStarterLogger;\n}\n\nconst envValue = (key: string, fallback = ''): string => {\n const value = typeof process !== 'undefined' && process.env ? process.env[key] : undefined;\n\n return value === undefined ? fallback : value;\n};\n\nconst maskPassword = (password: string): string => {\n return password ? 'xxxxxx' : 'empty';\n};\n\nconst splitStartOptions = (options: StartCouchbaseOptions = {}) => {\n const {logger, ...connectionOverrides} = options;\n\n return {connectionOverrides, logger};\n};\n\nexport const getConnectionOptions = (overrides: Partial<CouchsetArgs> = {}): CouchsetArgs => {\n const proxy = envValue('COUCHBASE_PROXY');\n const options: CouchsetArgs = {\n bucketName: envValue('COUCHBASE_BUCKET', 'dev'),\n connectionString: envValue('COUCHBASE_URL', 'couchbase://localhost'),\n password: envValue('COUCHBASE_PASSWORD', '1234'),\n username: envValue('COUCHBASE_USERNAME', 'admin'),\n };\n\n if (proxy) {\n options.proxy = proxy;\n }\n\n return {\n ...options,\n ...overrides,\n };\n};\n\nexport const connectionOptions: CouchsetArgs = getConnectionOptions();\n\nconst refreshConnectionOptions = (overrides: Partial<CouchsetArgs> = {}): CouchsetArgs => {\n const nextOptions = getConnectionOptions(overrides);\n\n Object.keys(connectionOptions).forEach((key) => {\n delete (connectionOptions as any)[key];\n });\n Object.assign(connectionOptions, nextOptions);\n\n return connectionOptions;\n};\n\nconst logConnectionStart = (\n options: CouchsetArgs,\n logger: CouchbaseStarterLogger | undefined,\n mode: string\n): void => {\n if (logger === false) {\n return;\n }\n\n const log = logger || console.log;\n\n log(\n 'Couchbase',\n 'starting',\n mode,\n JSON.stringify({\n bucket: options.bucketName,\n host: options.connectionString,\n password: maskPassword(options.password),\n username: options.username,\n })\n );\n};\n\nconst logConnectionStarted = (\n options: CouchsetArgs,\n logger: CouchbaseStarterLogger | undefined,\n mode: string\n): void => {\n if (logger === false) {\n return;\n }\n\n const log = logger || console.log;\n\n log(\n 'Couchbase',\n 'started',\n mode,\n JSON.stringify({bucket: options.bucketName, host: options.connectionString})\n );\n};\n\nexport const startCouchbase = async (options: StartCouchbaseOptions = {}): Promise<boolean> => {\n const {connectionOverrides, logger} = splitStartOptions(options);\n const resolvedOptions = refreshConnectionOptions(connectionOverrides);\n\n logConnectionStart(resolvedOptions, logger, 'standard');\n await CouchbaseConnection.Instance.init(resolvedOptions);\n logConnectionStarted(resolvedOptions, logger, 'standard');\n\n return true;\n};\n\nexport const startCouchbaseServerless = async (\n options: StartCouchbaseOptions = {}\n): Promise<boolean> => {\n const {connectionOverrides, logger} = splitStartOptions(options);\n const resolvedOptions = refreshConnectionOptions(connectionOverrides);\n\n logConnectionStart(resolvedOptions, logger, 'serverless');\n await CouchbaseConnection.Instance.initServerless(resolvedOptions);\n logConnectionStarted(resolvedOptions, logger, 'serverless');\n\n return true;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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","sourcesContent":["import CouchbaseConnection, {CouchsetArgs} from './connection';\n\nexport type CouchbaseStarterLogger = ((...args: any[]) => void) | false;\n\nexport interface StartCouchbaseOptions extends Partial<CouchsetArgs> {\n logger?: CouchbaseStarterLogger;\n}\n\nconst envValue = (key: string, fallback = ''): string => {\n const value = typeof process !== 'undefined' && process.env ? process.env[key] : undefined;\n\n return value === undefined ? fallback : value;\n};\n\nconst databaseUrlError = (reason: string): Error =>\n new Error(`DB_URL must use couchbase:// or couchbases://user:password@host/bucket: ${reason}`);\n\nconst decodeDatabaseUrlComponent = (value: string, label: string): string => {\n try {\n return decodeURIComponent(value);\n } catch (_error) {\n throw databaseUrlError(`${label} contains invalid percent-encoding`);\n }\n};\n\n/**\n * Convert a PostgreSQL-style DB_URL into Couchbase SDK connection settings.\n * The bucket lives in the URL path; it is not part of Couchbase's connection\n * string, which contains only the scheme, host, optional port, and options.\n */\nexport const parseDatabaseUrl = (\n value: string\n): Pick<CouchsetArgs, 'bucketName' | 'connectionString' | 'password' | 'username'> => {\n let url: URL;\n\n try {\n url = new URL(value);\n } catch (_error) {\n throw databaseUrlError('the value is not a valid URL');\n }\n\n if (url.protocol !== 'couchbase:' && url.protocol !== 'couchbases:') {\n throw databaseUrlError(`unsupported protocol ${url.protocol || '(missing)'}`);\n }\n if (!url.hostname) {\n throw databaseUrlError('a host is required');\n }\n if (!url.username || !url.password) {\n throw databaseUrlError('a username and password are required');\n }\n if (url.hash) {\n throw databaseUrlError('fragments are not supported');\n }\n\n const bucketName = decodeDatabaseUrlComponent(\n url.pathname.replace(/^\\//, ''),\n 'the bucket name'\n );\n if (!bucketName || bucketName.indexOf('/') !== -1) {\n throw databaseUrlError('the path must contain exactly one bucket name');\n }\n\n return {\n bucketName,\n connectionString: `${url.protocol}//${url.host}${url.search}`,\n password: decodeDatabaseUrlComponent(url.password, 'the password'),\n username: decodeDatabaseUrlComponent(url.username, 'the username'),\n };\n};\n\nconst maskPassword = (password: string): string => {\n return password ? 'xxxxxx' : 'empty';\n};\n\nconst splitStartOptions = (options: StartCouchbaseOptions = {}) => {\n const {logger, ...connectionOverrides} = options;\n\n return {connectionOverrides, logger};\n};\n\nexport const getConnectionOptions = (overrides: Partial<CouchsetArgs> = {}): CouchsetArgs => {\n const proxy = envValue('COUCHBASE_PROXY');\n const databaseUrl = envValue('DB_URL');\n const options: CouchsetArgs = {\n bucketName: envValue('COUCHBASE_BUCKET', 'dev'),\n connectionString: envValue('COUCHBASE_URL', 'couchbase://localhost'),\n password: envValue('COUCHBASE_PASSWORD', '1234'),\n username: envValue('COUCHBASE_USERNAME', 'admin'),\n };\n\n if (proxy) {\n options.proxy = proxy;\n }\n\n return {\n ...options,\n ...(databaseUrl ? parseDatabaseUrl(databaseUrl) : {}),\n ...overrides,\n };\n};\n\nexport const connectionOptions: CouchsetArgs = getConnectionOptions();\n\nconst refreshConnectionOptions = (overrides: Partial<CouchsetArgs> = {}): CouchsetArgs => {\n const nextOptions = getConnectionOptions(overrides);\n\n Object.keys(connectionOptions).forEach((key) => {\n delete (connectionOptions as any)[key];\n });\n Object.assign(connectionOptions, nextOptions);\n\n return connectionOptions;\n};\n\nconst logConnectionStart = (\n options: CouchsetArgs,\n logger: CouchbaseStarterLogger | undefined,\n mode: string\n): void => {\n if (logger === false) {\n return;\n }\n\n const log = logger || console.log;\n\n log(\n 'Couchbase',\n 'starting',\n mode,\n JSON.stringify({\n bucket: options.bucketName,\n host: options.connectionString,\n password: maskPassword(options.password),\n username: options.username,\n })\n );\n};\n\nconst logConnectionStarted = (\n options: CouchsetArgs,\n logger: CouchbaseStarterLogger | undefined,\n mode: string\n): void => {\n if (logger === false) {\n return;\n }\n\n const log = logger || console.log;\n\n log(\n 'Couchbase',\n 'started',\n mode,\n JSON.stringify({bucket: options.bucketName, host: options.connectionString})\n );\n};\n\nexport const startCouchbase = async (options: StartCouchbaseOptions = {}): Promise<boolean> => {\n const {connectionOverrides, logger} = splitStartOptions(options);\n const resolvedOptions = refreshConnectionOptions(connectionOverrides);\n\n logConnectionStart(resolvedOptions, logger, 'standard');\n await CouchbaseConnection.Instance.init(resolvedOptions);\n logConnectionStarted(resolvedOptions, logger, 'standard');\n\n return true;\n};\n\nexport const startCouchbaseServerless = async (\n options: StartCouchbaseOptions = {}\n): Promise<boolean> => {\n const {connectionOverrides, logger} = splitStartOptions(options);\n const resolvedOptions = refreshConnectionOptions(connectionOverrides);\n\n logConnectionStart(resolvedOptions, logger, 'serverless');\n await CouchbaseConnection.Instance.initServerless(resolvedOptions);\n logConnectionStarted(resolvedOptions, logger, 'serverless');\n\n return true;\n};\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface PathSegment {
|
|
2
|
+
name: string;
|
|
3
|
+
selectors: string[];
|
|
4
|
+
}
|
|
5
|
+
/** Parse data paths, not SQL expressions. Backticks delimit literal field names. */
|
|
6
|
+
export declare const parseFieldPath: (path: string) => PathSegment[];
|
|
7
|
+
export declare const renderFieldPath: (segments: readonly PathSegment[]) => string;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderFieldPath = exports.parseFieldPath = void 0;
|
|
4
|
+
var keyspace_1 = require("./keyspace");
|
|
5
|
+
/** Parse data paths, not SQL expressions. Backticks delimit literal field names. */
|
|
6
|
+
var parseFieldPath = function (path) {
|
|
7
|
+
var invalid = function () {
|
|
8
|
+
throw new Error("Invalid field path: ".concat(JSON.stringify(path)));
|
|
9
|
+
};
|
|
10
|
+
if (typeof path !== 'string' || !path.length || /[\x00-\x1f\x7f]/.test(path))
|
|
11
|
+
invalid();
|
|
12
|
+
var segments = [];
|
|
13
|
+
var position = 0;
|
|
14
|
+
while (position < path.length) {
|
|
15
|
+
var name_1 = '';
|
|
16
|
+
if (path[position] === '`') {
|
|
17
|
+
position++;
|
|
18
|
+
var closed_1 = false;
|
|
19
|
+
while (position < path.length) {
|
|
20
|
+
var character = path[position++];
|
|
21
|
+
if (character !== '`')
|
|
22
|
+
name_1 += character;
|
|
23
|
+
else if (path[position] === '`') {
|
|
24
|
+
name_1 += '`';
|
|
25
|
+
position++;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
closed_1 = true;
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (!closed_1)
|
|
33
|
+
invalid();
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
while (position < path.length && !'.[]'.includes(path[position])) {
|
|
37
|
+
name_1 += path[position++];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (!name_1)
|
|
41
|
+
invalid();
|
|
42
|
+
var selectors = [];
|
|
43
|
+
while (path[position] === '[') {
|
|
44
|
+
var end = path.indexOf(']', position + 1);
|
|
45
|
+
if (end < 0)
|
|
46
|
+
invalid();
|
|
47
|
+
var selector = path.slice(position + 1, end);
|
|
48
|
+
if (selector !== '*' &&
|
|
49
|
+
(!/^(0|[1-9]\d*)$/.test(selector) || !Number.isSafeInteger(Number(selector))))
|
|
50
|
+
invalid();
|
|
51
|
+
selectors.push("[".concat(selector, "]"));
|
|
52
|
+
position = end + 1;
|
|
53
|
+
}
|
|
54
|
+
segments.push({ name: name_1, selectors: selectors });
|
|
55
|
+
if (position === path.length)
|
|
56
|
+
break;
|
|
57
|
+
if (path[position++] !== '.' || position === path.length)
|
|
58
|
+
invalid();
|
|
59
|
+
}
|
|
60
|
+
return segments;
|
|
61
|
+
};
|
|
62
|
+
exports.parseFieldPath = parseFieldPath;
|
|
63
|
+
var renderFieldPath = function (segments) {
|
|
64
|
+
return segments.map(function (_a) {
|
|
65
|
+
var name = _a.name, selectors = _a.selectors;
|
|
66
|
+
return (0, keyspace_1.escapeIdentifier)(name) + selectors.join('');
|
|
67
|
+
}).join('.');
|
|
68
|
+
};
|
|
69
|
+
exports.renderFieldPath = renderFieldPath;
|
|
70
|
+
//# sourceMappingURL=field-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-path.js","sourceRoot":"","sources":["../../src/model/field-path.ts"],"names":[],"mappings":"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","sourcesContent":["import {escapeIdentifier} from './keyspace';\n\ninterface PathSegment {\n name: string;\n selectors: string[];\n}\n\n/** Parse data paths, not SQL expressions. Backticks delimit literal field names. */\nexport const parseFieldPath = (path: string): PathSegment[] => {\n const invalid = (): never => {\n throw new Error(`Invalid field path: ${JSON.stringify(path)}`);\n };\n if (typeof path !== 'string' || !path.length || /[\\x00-\\x1f\\x7f]/.test(path)) invalid();\n const segments: PathSegment[] = [];\n let position = 0;\n while (position < path.length) {\n let name = '';\n if (path[position] === '`') {\n position++;\n let closed = false;\n while (position < path.length) {\n const character = path[position++];\n if (character !== '`') name += character;\n else if (path[position] === '`') {\n name += '`';\n position++;\n } else {\n closed = true;\n break;\n }\n }\n if (!closed) invalid();\n } else {\n while (position < path.length && !'.[]'.includes(path[position])) {\n name += path[position++];\n }\n }\n if (!name) invalid();\n const selectors: string[] = [];\n while (path[position] === '[') {\n const end = path.indexOf(']', position + 1);\n if (end < 0) invalid();\n const selector = path.slice(position + 1, end);\n if (\n selector !== '*' &&\n (!/^(0|[1-9]\\d*)$/.test(selector) || !Number.isSafeInteger(Number(selector)))\n )\n invalid();\n selectors.push(`[${selector}]`);\n position = end + 1;\n }\n segments.push({name, selectors});\n if (position === path.length) break;\n if (path[position++] !== '.' || position === path.length) invalid();\n }\n return segments;\n};\n\nexport const renderFieldPath = (segments: readonly PathSegment[]): string =>\n segments.map(({name, selectors}) => escapeIdentifier(name) + selectors.join('')).join('.');\n"]}
|
package/dist/model/include.d.ts
CHANGED
|
@@ -2,22 +2,47 @@ import { LogicalWhereExpr, SortType } from '../query/interface/query.types';
|
|
|
2
2
|
export type IncludeType = 'join' | 'leftJoin' | 'nest' | 'leftNest';
|
|
3
3
|
export interface IncludeDefinition {
|
|
4
4
|
as: string;
|
|
5
|
+
/** ANSI predicate; mutually exclusive with key/keys. */
|
|
6
|
+
on?: JoinPredicate;
|
|
7
|
+
/** Explicit trusted SQL++ escape hatch. Values still use positional placeholders. */
|
|
8
|
+
onRaw?: {
|
|
9
|
+
sql: string;
|
|
10
|
+
values?: readonly unknown[];
|
|
11
|
+
};
|
|
12
|
+
/** Top-level fields retained from the related document. */
|
|
13
|
+
select?: readonly string[];
|
|
5
14
|
key?: string;
|
|
6
15
|
keys?: string;
|
|
7
16
|
keyspace?: string;
|
|
8
17
|
model?: string | {
|
|
9
18
|
keyspace: () => string;
|
|
19
|
+
parse?: <T>(data: T) => T;
|
|
20
|
+
parseProjection?: <T>(data: T) => T;
|
|
10
21
|
};
|
|
11
22
|
type?: IncludeType;
|
|
12
23
|
optional?: boolean;
|
|
13
24
|
}
|
|
25
|
+
/** A field operand is explicit; bare strings are always parameter values. */
|
|
26
|
+
export interface JoinField {
|
|
27
|
+
readonly $field: string;
|
|
28
|
+
}
|
|
29
|
+
export type JoinPredicate = {
|
|
30
|
+
$and: readonly JoinPredicate[];
|
|
31
|
+
} | {
|
|
32
|
+
$or: readonly JoinPredicate[];
|
|
33
|
+
} | {
|
|
34
|
+
left: JoinField;
|
|
35
|
+
op: '$eq' | '$neq' | '$gt' | '$gte' | '$lt' | '$lte';
|
|
36
|
+
right: unknown;
|
|
37
|
+
};
|
|
38
|
+
export declare const joinField: (path: string) => JoinField;
|
|
14
39
|
export interface IncludedSelectionQueryArgs {
|
|
15
40
|
keyspace: string;
|
|
16
41
|
collectionName: string;
|
|
17
|
-
select?: any[] | string;
|
|
42
|
+
select?: readonly any[] | string;
|
|
18
43
|
where?: LogicalWhereExpr;
|
|
19
44
|
orderBy?: Record<string, SortType>;
|
|
20
|
-
include?: IncludeDefinition[];
|
|
45
|
+
include?: readonly IncludeDefinition[];
|
|
21
46
|
limit?: number;
|
|
22
47
|
page?: number;
|
|
23
48
|
offset?: number;
|
|
@@ -29,5 +54,13 @@ export interface IncludedSelectionQuery {
|
|
|
29
54
|
selectAll: boolean;
|
|
30
55
|
resultKey?: string;
|
|
31
56
|
}
|
|
32
|
-
|
|
57
|
+
declare class IncludeParameterStore {
|
|
58
|
+
parameters: Record<string, any>;
|
|
59
|
+
private index;
|
|
60
|
+
add(value: any): string;
|
|
61
|
+
set(key: string, value: any): string;
|
|
62
|
+
}
|
|
63
|
+
export declare const includeOperator: (include: IncludeDefinition) => string;
|
|
64
|
+
export declare const buildIncludeClauses: (keyspace: string, include?: readonly IncludeDefinition[], sourceAlias?: string, store?: IncludeParameterStore) => string;
|
|
33
65
|
export declare const buildIncludedSelectionQuery: (args: IncludedSelectionQueryArgs) => IncludedSelectionQuery;
|
|
66
|
+
export {};
|