Skip to content

Commit 514417a

Browse files
authored
Misc fixes and refactors (#61)
* headers integration testing * better encapsulation on the core classes * let data api return unauthenticated error directly * fixed rebasing mistake * updated non-astra example to use updateDbNamespace * slightl update to non-astra example * tiny update to ObjectIDs internal representation * reinstated example deps to npm versions * DefaultEmbeddingHeadersProvider => EmbeddingAPIKeyHeaderProvider * removed unused var
1 parent 2a9efce commit 514417a

File tree

19 files changed

+216
-206
lines changed

19 files changed

+216
-206
lines changed

etc/astra-db-ts.api.md

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ export class AstraAdmin {
115115
// @public
116116
export class AstraDbAdmin extends DbAdmin {
117117
// @internal
118-
constructor(db: Db, rootOpts: InternalRootClientOpts, adminOpts?: AdminSpawnOptions);
119-
createNamespace(namespace: string, options?: AdminBlockingOptions): Promise<void>;
118+
constructor(db: Db, rootOpts: InternalRootClientOpts, adminOpts: AdminSpawnOptions | undefined, dbToken: TokenProvider);
119+
createNamespace(namespace: string, options?: CreateNamespaceOptions): Promise<void>;
120120
db(): Db;
121121
drop(options?: AdminBlockingOptions): Promise<void>;
122122
dropNamespace(namespace: string, options?: AdminBlockingOptions): Promise<void>;
@@ -125,6 +125,12 @@ export class AstraDbAdmin extends DbAdmin {
125125
listNamespaces(options?: WithTimeout): Promise<string[]>;
126126
}
127127

128+
// @public
129+
export class AWSEmbeddingHeadersProvider extends EmbeddingHeadersProvider {
130+
constructor(accessKeyId: string, secretAccessKey: string);
131+
getHeaders(): Record<string, string>;
132+
}
133+
128134
// @public
129135
export class BulkWriteError extends CumulativeDataAPIError {
130136
name: string;
@@ -230,8 +236,8 @@ export interface CollectionOptions<Schema extends SomeDoc> {
230236

231237
// @public
232238
export interface CollectionSpawnOptions extends WithNamespace {
233-
defaultMaxTimeMS?: number;
234-
embeddingApiKey?: string;
239+
defaultMaxTimeMS?: number | null;
240+
embeddingApiKey?: string | EmbeddingHeadersProvider | null;
235241
}
236242

237243
// @public
@@ -301,7 +307,7 @@ export type CreateDatabaseOptions = AdminBlockingOptions & {
301307

302308
// @public
303309
export type CreateNamespaceOptions = AdminBlockingOptions & {
304-
replication?: NamespaceReplicationOptions;
310+
updateDbNamespace?: boolean;
305311
};
306312

307313
// @public
@@ -371,7 +377,7 @@ export type DataAPICommandEvents = {
371377
export class DataAPIDbAdmin extends DbAdmin {
372378
// @internal
373379
constructor(db: Db, httpClient: DataAPIHttpClient, adminOpts?: AdminSpawnOptions);
374-
createNamespace(namespace: string, options?: CreateNamespaceOptions): Promise<void>;
380+
createNamespace(namespace: string, options?: LocalCreateNamespaceOptions): Promise<void>;
375381
db(): Db;
376382
dropNamespace(namespace: string, options?: AdminBlockingOptions): Promise<void>;
377383
listNamespaces(options?: WithTimeout): Promise<string[]>;
@@ -526,12 +532,13 @@ export class Db {
526532
listCollections(options?: ListCollectionsOptions & {
527533
nameOnly?: false;
528534
}): Promise<FullCollectionInfo[]>;
529-
readonly namespace: string;
535+
get namespace(): string;
536+
useNamespace(namespace: string): void;
530537
}
531538

532539
// @public
533540
export abstract class DbAdmin {
534-
abstract createNamespace(namespace: string, options?: AdminBlockingOptions): Promise<void>;
541+
abstract createNamespace(namespace: string, options?: CreateNamespaceOptions): Promise<void>;
535542
abstract db(): Db;
536543
abstract dropNamespace(namespace: string, options?: AdminBlockingOptions): Promise<void>;
537544
abstract listNamespaces(): Promise<string[]>;
@@ -553,6 +560,12 @@ export interface DbSpawnOptions {
553560
token?: string | TokenProvider | null;
554561
}
555562

563+
// @public
564+
export class EmbeddingAPIKeyHeaderProvider extends EmbeddingHeadersProvider {
565+
constructor(apiKey: string | nullish);
566+
getHeaders(): Record<string, string>;
567+
}
568+
556569
// @public
557570
export interface DefaultHttpClientOptions {
558571
client?: 'default';
@@ -641,6 +654,13 @@ export class DevOpsUnexpectedStateError extends DevOpsAPIError {
641654
export interface DropCollectionOptions extends WithTimeout, WithNamespace {
642655
}
643656

657+
// @public
658+
export abstract class EmbeddingHeadersProvider {
659+
abstract getHeaders(): Promise<Record<string, string>> | Record<string, string>;
660+
// @internal
661+
static parseHeaders(token: unknown): EmbeddingHeadersProvider;
662+
}
663+
644664
// @public
645665
export class FailedToLoadDefaultClientError extends Error {
646666
// @internal
@@ -935,6 +955,11 @@ export interface ListDatabasesOptions extends WithTimeout {
935955
skip?: number;
936956
}
937957

958+
// @public
959+
export type LocalCreateNamespaceOptions = CreateNamespaceOptions & {
960+
replication?: NamespaceReplicationOptions;
961+
};
962+
938963
// @public
939964
export type MaybeId<T> = NoId<T> & {
940965
_id?: IdOf<T>;
@@ -1076,7 +1101,7 @@ export type SortDirection = 1 | -1 | 'asc' | 'desc' | 'ascending' | 'descending'
10761101
// @public
10771102
export class StaticTokenProvider extends TokenProvider {
10781103
constructor(token: string | nullish);
1079-
getToken(): Promise<string | nullish>;
1104+
getToken(): string | nullish;
10801105
}
10811106

10821107
// @public
@@ -1168,7 +1193,7 @@ export type ToDotNotation<Schema extends SomeDoc> = Merge<_ToDotNotation<Schema,
11681193

11691194
// @public
11701195
export abstract class TokenProvider {
1171-
abstract getToken(): Promise<string | nullish>;
1196+
abstract getToken(): string | nullish | Promise<string | nullish>;
11721197
// @internal
11731198
static parseToken(token: unknown): TokenProvider;
11741199
}
@@ -1256,7 +1281,7 @@ export interface UpsertedUpdateOptions<Schema extends SomeDoc> {
12561281
// @public
12571282
export class UsernamePasswordTokenProvider extends TokenProvider {
12581283
constructor(username: string, password: string);
1259-
getToken(): Promise<string>;
1284+
getToken(): string;
12601285
}
12611286

12621287
// @public

examples/non-astra-backends/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,14 @@ const db = client.db('http://localhost:8181', { token: tp });
4848
const dbAdmin = db.admin({ environment: 'dse' });
4949

5050
(async () => {
51-
await dbAdmin.createNamespace('my_keyspace');
51+
await dbAdmin.createNamespace('my_keyspace', {
52+
updateDbNamespace: true,
53+
});
54+
5255
console.log(await dbAdmin.listNamespaces());
56+
57+
const collection = await db.createCollection('my_coll', {
58+
checkExists: false,
59+
});
5360
})();
5461
```
Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,40 @@
1-
import { DataAPIClient, UsernamePasswordTokenProvider } from '@datastax/astra-db-ts';
1+
import { DataAPIClient, UsernamePasswordTokenProvider, UUID } from '@datastax/astra-db-ts';
22

3-
// Creates the client. Need to pass in the environment parameter so `astra-db-ts` can adjust properly.
3+
// Creates the client. Need to pass in the environment parameter so `astra-db-ts` can adjust properly
44
const client = new DataAPIClient({ environment: 'dse' });
55

66
// Use the token provide to set up your credentials easily
77
const tp = new UsernamePasswordTokenProvider('cassandra', 'cassandra');
8+
9+
// Creates a Db without a namespace
10+
// The namespace will be set later when doing `createNamespace`
811
const db = client.db('http://localhost:8181', { token: tp });
912

1013
// db.admin() needs the environment passed in for proper typing purposes
1114
// Note that it's typed as returning 'DataAPIDbAdmin' instead of 'DbAdmin' or 'AstraDbAdmin'
1215
const dbAdmin = db.admin({ environment: 'dse' });
1316

14-
// Creates a new namespace and lists all namespaces that now exist
15-
// Note that the db is not properly configured to use the keyspace that's just been created yet.
1617
(async () => {
17-
await dbAdmin.createNamespace('my_keyspace');
18+
// Creates the new namespace 'my_keyspace'
19+
// The Db that spawned the DbAdmin is updated to use the new namespace
20+
await dbAdmin.createNamespace('my_keyspace', {
21+
updateDbNamespace: true,
22+
});
23+
24+
// The list of namespaces will now include 'my_keyspace'
1825
console.log(await dbAdmin.listNamespaces());
26+
27+
// Creates a collection in the 'my_keyspace' namespace
28+
const collection = await db.createCollection('my_coll', {
29+
checkExists: false,
30+
});
31+
32+
// Example of document manipulation in the newly created namespace
33+
const _id = UUID.v7();
34+
35+
await collection.insertOne({ _id });
36+
37+
console.log(await collection.findOne({}))
38+
39+
await collection.deleteOne({ _id });
1940
})();

src/api/clients/data-api-http-client.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ export const EmissionStrategy: Record<'Normal' | 'Admin', EmissionStrategy> = {
9090
const adaptInfo4Devops = (info: DataAPIRequestInfo) => (<const>{
9191
method: 'POST',
9292
data: info.command,
93-
params: {},
9493
path: info.url,
94+
params: {},
9595
});
9696

9797
interface DataAPIHttpClientOpts extends HTTPClientOptions {
@@ -197,11 +197,6 @@ export class DataAPIHttpClient extends HttpClient {
197197

198198
const data: RawDataAPIResponse = resp.body ? JSON.parse(resp.body, reviver) : {};
199199

200-
if (resp.status === 401 || (data.errors && data.errors.length > 0 && data.errors[0]?.message === 'UNAUTHENTICATED: Invalid token')) {
201-
const fauxResponse = mkFauxErroredResponse('Authentication failed; is your token valid?');
202-
throw mkRespErrorFromResponse(DataAPIResponseError, info.command, fauxResponse);
203-
}
204-
205200
if (data.errors && data.errors.length > 0 && data.errors[0]?.errorCode === 'COLLECTION_NOT_EXIST') {
206201
const name = data.errors[0]?.message.split(': ')[1];
207202
throw new CollectionNotFoundError(info.namespace ?? '<unknown>', name);
@@ -231,10 +226,6 @@ export class DataAPIHttpClient extends HttpClient {
231226
}
232227
}
233228

234-
const mkFauxErroredResponse = (message: string): RawDataAPIResponse => {
235-
return { errors: [{ message }] };
236-
}
237-
238229
/**
239230
* @internal
240231
*/

src/api/clients/http-client.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ export abstract class HttpClient {
2727
readonly monitorCommands: boolean;
2828
readonly fetchCtx: FetchCtx;
2929
readonly baseHeaders: Record<string, any>;
30+
readonly headerProviders: HeaderProvider[];
3031

31-
protected constructor(options: HTTPClientOptions, readonly headerProviders: HeaderProvider[]) {
32+
protected constructor(options: HTTPClientOptions, headerProviders: HeaderProvider[]) {
3233
this.baseUrl = options.baseUrl;
3334
this.emitter = options.emitter;
3435
this.monitorCommands = options.monitorCommands;
@@ -41,6 +42,8 @@ export abstract class HttpClient {
4142
this.baseHeaders = {};
4243
this.baseHeaders['User-Agent'] = options.userAgent;
4344
this.baseHeaders['Content-Type'] = 'application/json';
45+
46+
this.headerProviders = headerProviders;
4447
}
4548

4649
protected async _request(info: HTTPRequestInfo): Promise<FetcherResponseInfo> {

src/api/constants.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,6 @@ export const DEFAULT_NAMESPACE = 'default_keyspace';
5353
*/
5454
export const DEFAULT_TIMEOUT = 30000;
5555

56-
/**
57-
* @internal
58-
*/
59-
export const DEFAULT_EMBEDDING_API_KEY_HEADER = 'x-embedding-api-key';
60-
6156
/**
6257
* @internal
6358
*/

0 commit comments

Comments
 (0)