diff --git a/etc/astra-db-ts.api.md b/etc/astra-db-ts.api.md index fe9dcf9b..6748d2dc 100644 --- a/etc/astra-db-ts.api.md +++ b/etc/astra-db-ts.api.md @@ -34,16 +34,19 @@ export abstract class AdminCommandEvent extends DataAPIClientEvent { // Warning: (ae-forgotten-export) The symbol "DevOpsAPIRequestInfo" needs to be exported by the entry point index.d.ts // // @internal - protected constructor(info: DevOpsAPIRequestInfo, longRunning: boolean); + protected constructor(name: string, info: DevOpsAPIRequestInfo, longRunning: boolean); + // @internal (undocumented) + protected _desc(): string; readonly longRunning: boolean; readonly method: 'GET' | 'POST' | 'DELETE'; + readonly methodName: string; readonly params?: Record; readonly path: string; readonly reqBody?: Record; } // @public -export type AdminCommandEvents = { +export type AdminCommandEventMap = { adminCommandStarted: (event: AdminCommandStartedEvent) => void; adminCommandPolling: (event: AdminCommandPollingEvent) => void; adminCommandSucceeded: (event: AdminCommandSucceededEvent) => void; @@ -75,10 +78,10 @@ export class AdminCommandPollingEvent extends AdminCommandEvent { // @public export class AdminCommandStartedEvent extends AdminCommandEvent { // @internal - constructor(info: DevOpsAPIRequestInfo, longRunning: boolean, timeout: number); + constructor(info: DevOpsAPIRequestInfo, longRunning: boolean, timeout: Partial); // (undocumented) formatted(): string; - readonly timeout: number; + readonly timeout: Partial; } // @public @@ -101,12 +104,13 @@ export class AdminCommandWarningsEvent extends AdminCommandEvent { } // @public -export interface AdminSpawnOptions { +export interface AdminOptions { additionalHeaders?: Record; adminToken?: string | TokenProvider | null; astraEnv?: 'dev' | 'prod' | 'test'; endpointUrl?: string; logging?: DataAPILoggingConfig; + timeoutDefaults?: Partial; } // @public (undocumented) @@ -122,7 +126,7 @@ export interface AlterTableOperations { } // @public (undocumented) -export interface AlterTableOptions extends WithTimeout { +export interface AlterTableOptions extends WithTimeout<'tableAdminTimeoutMs'> { // (undocumented) operation: AlterTableOperations; } @@ -130,32 +134,19 @@ export interface AlterTableOptions extends WithTimeout { // @public (undocumented) export type AlterTableSchema> = Normalize, Cols2Drop>>; -// @public -export interface ArrayFilterOps { - $all?: Elem; - $size?: number; -} - -// Warning: (ae-forgotten-export) The symbol "PickArrayTypes" needs to be exported by the entry point index.d.ts -// -// @public -export type ArrayUpdate = { - [K in keyof Schema as any[] extends Schema[K] ? K : never]?: PickArrayTypes; -}; - // @public export class AstraAdmin { // Warning: (ae-forgotten-export) The symbol "InternalRootClientOpts" needs to be exported by the entry point index.d.ts // // @internal - constructor(rootOpts: InternalRootClientOpts, rawAdminOpts?: AdminSpawnOptions); + constructor(rootOpts: InternalRootClientOpts, rawAdminOpts?: AdminOptions); createDatabase(config: AstraDatabaseConfig, options?: CreateAstraDatabaseOptions): Promise; - db(endpoint: string, options?: DbSpawnOptions): Db; - db(id: string, region: string, options?: DbSpawnOptions): Db; - dbAdmin(endpoint: string, options?: DbSpawnOptions): AstraDbAdmin; - dbAdmin(id: string, region: string, options?: DbSpawnOptions): AstraDbAdmin; - dbInfo(id: string, options?: WithTimeout): Promise; - dropDatabase(db: Db | string, options?: AstraAdminBlockingOptions): Promise; + db(endpoint: string, options?: DbOptions): Db; + db(id: string, region: string, options?: DbOptions): Db; + dbAdmin(endpoint: string, options?: DbOptions): AstraDbAdmin; + dbAdmin(id: string, region: string, options?: DbOptions): AstraDbAdmin; + dbInfo(id: string, options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise; + dropDatabase(db: Db | string, options?: DropAstraDatabaseOptions): Promise; // Warning: (ae-forgotten-export) The symbol "DevOpsAPIHttpClient" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -167,7 +158,7 @@ export class AstraAdmin { export type AstraAdminBlockingOptions = AstraPollBlockingOptions | AstraNoBlockingOptions; // @public -export type AstraCreateKeyspaceOptions = AstraAdminBlockingOptions & { +export type AstraCreateKeyspaceOptions = AstraAdminBlockingOptions & WithTimeout<'keyspaceAdminTimeoutMs'> & { updateDbKeyspace?: boolean; }; @@ -182,30 +173,25 @@ export interface AstraDatabaseConfig { // @public export class AstraDbAdmin extends DbAdmin { // @internal - constructor(db: Db, rootOpts: InternalRootClientOpts, rawAdminOpts: AdminSpawnOptions | undefined, dbToken: TokenProvider | undefined, endpoint: string); + constructor(db: Db, rootOpts: InternalRootClientOpts, rawAdminOpts: AdminOptions | undefined, dbToken: TokenProvider | undefined, endpoint: string); createKeyspace(keyspace: string, options?: AstraCreateKeyspaceOptions): Promise; db(): Db; - drop(options?: AstraAdminBlockingOptions): Promise; - dropKeyspace(keyspace: string, options?: AstraAdminBlockingOptions): Promise; - findEmbeddingProviders(options?: WithTimeout): Promise; + drop(options?: AstraDropKeyspaceOptions): Promise; + dropKeyspace(keyspace: string, options?: AstraDropKeyspaceOptions): Promise; + findEmbeddingProviders(options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise; // (undocumented) get _httpClient(): DevOpsAPIHttpClient; get id(): string; - info(options?: WithTimeout): Promise; - listKeyspaces(options?: WithTimeout): Promise; + info(options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise; + listKeyspaces(options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise; } -// @public (undocumented) +// @public export interface AstraDbAdminInfo extends BaseAstraDbInfo { - // (undocumented) createdAt: Date; - // (undocumented) lastUsed: Date; - // (undocumented) orgId: string; - // (undocumented) ownerId: string; - // (undocumented) regions: AstraDbRegionInfo[]; } @@ -215,7 +201,7 @@ export type AstraDbCloudProvider = 'AWS' | 'GCP' | 'AZURE'; // @public export type AstraDbCloudProviderFilter = AstraDbCloudProvider | 'ALL'; -// @public (undocumented) +// @public export interface AstraDbInfo extends BaseAstraDbInfo { // (undocumented) apiEndpoint: string; @@ -223,13 +209,10 @@ export interface AstraDbInfo extends BaseAstraDbInfo { region: string; } -// @public (undocumented) +// @public export interface AstraDbRegionInfo { - // (undocumented) apiEndpoint: string; - // (undocumented) createdAt: Date; - // (undocumented) name: string; } @@ -239,13 +222,16 @@ export type AstraDbStatus = 'ACTIVE' | 'ERROR' | 'DECOMMISSIONING' | 'DEGRADED' // @public export type AstraDbStatusFilter = AstraDbStatus | 'ALL' | 'NONTERMINATED'; +// @public (undocumented) +export type AstraDropKeyspaceOptions = AstraAdminBlockingOptions & WithTimeout<'keyspaceAdminTimeoutMs'>; + // @public -export interface AstraNoBlockingOptions extends WithTimeout { +export interface AstraNoBlockingOptions { blocking: false; } // @public -export interface AstraPollBlockingOptions extends WithTimeout { +export interface AstraPollBlockingOptions { blocking?: true; pollInterval?: number; } @@ -256,21 +242,14 @@ export class AWSEmbeddingHeadersProvider extends EmbeddingHeadersProvider { getHeaders(): Record; } -// @public (undocumented) +// @public export interface BaseAstraDbInfo { - // (undocumented) cloudProvider: AstraDbCloudProvider; - // (undocumented) environment: 'dev' | 'test' | 'prod'; - // (undocumented) id: string; - // (undocumented) keyspaces: string[]; - // (undocumented) name: string; - // (undocumented) raw: Record; - // (undocumented) status: AstraDbStatus; } @@ -282,40 +261,84 @@ export class Collection { // Warning: (ae-forgotten-export) The symbol "DataAPIHttpClient" needs to be exported by the entry point index.d.ts // // @internal - constructor(db: Db, httpClient: DataAPIHttpClient, name: string, opts: CollectionSpawnOptions | undefined); - countDocuments(filter: Filter, upperBound: number, options?: WithTimeout): Promise; - deleteMany(filter: Filter, options?: WithTimeout): Promise; - deleteOne(filter: Filter, options?: CollectionDeleteOneOptions): Promise; - distinct(key: Key, filter: Filter): Promise>)[Key]>[]>; - drop(options?: WithTimeout): Promise; - estimatedDocumentCount(options?: WithTimeout): Promise; - find(filter: Filter, options?: CollectionFindOptions & { + constructor(db: Db, httpClient: DataAPIHttpClient, name: string, opts: CollectionOptions | undefined); + countDocuments(filter: CollectionFilter, upperBound: number, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise; + deleteMany(filter: CollectionFilter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise; + deleteOne(filter: CollectionFilter, options?: CollectionDeleteOneOptions): Promise; + distinct(key: Key, filter: CollectionFilter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise>)[Key]>[]>; + drop(options?: WithTimeout<'collectionAdminTimeoutMs'>): Promise; + estimatedDocumentCount(options?: WithTimeout<'generalMethodTimeoutMs'>): Promise; + find(filter: CollectionFilter, options?: CollectionFindOptions & { projection?: never; - }): FindCursor, FoundDoc>; - find>(filter: Filter, options: CollectionFindOptions): FindCursor, FoundDoc>; - findOne(filter: Filter, options?: CollectionFindOneOptions & { + }): CollectionFindCursor, FoundDoc>; + find>(filter: CollectionFilter, options: CollectionFindOptions): CollectionFindCursor, FoundDoc>; + findOne(filter: CollectionFilter, options?: CollectionFindOneOptions & { projection?: never; }): Promise | null>; - findOne>(filter: Filter, options: CollectionFindOneOptions): Promise | null>; - findOneAndDelete>(filter: Filter, options?: CollectionFindOneAndDeleteOptions): Promise; - findOneAndReplace>(filter: Filter, replacement: NoId, options?: CollectionFindOneAndReplaceOptions): Promise; - findOneAndUpdate(filter: Filter, update: UpdateFilter, options?: CollectionFindOneAndUpdateOptions): Promise | null>; - get _httpClient(): DataAPIHttpClient; - insertMany(documents: MaybeId[], options?: CollectionInsertManyOptions): Promise>; - insertOne(document: MaybeId, options?: WithTimeout): Promise>; + findOne>(filter: CollectionFilter, options: CollectionFindOneOptions): Promise | null>; + findOneAndDelete>(filter: CollectionFilter, options?: CollectionFindOneAndDeleteOptions): Promise; + findOneAndReplace>(filter: CollectionFilter, replacement: NoId, options?: CollectionFindOneAndReplaceOptions): Promise; + findOneAndUpdate(filter: CollectionFilter, update: CollectionUpdateFilter, options?: CollectionFindOneAndUpdateOptions): Promise | null>; + get _httpClient(): DataAPIHttpClient<"normal">; + insertMany(documents: readonly MaybeId[], options?: CollectionInsertManyOptions): Promise>; + insertOne(document: MaybeId, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise>; readonly keyspace: string; readonly name: string; - options(options?: WithTimeout): Promise>; - replaceOne(filter: Filter, replacement: NoId, options?: CollectionReplaceOneOptions): Promise>; - updateMany(filter: Filter, update: UpdateFilter, options?: CollectionUpdateManyOptions): Promise>; - updateOne(filter: Filter, update: UpdateFilter, options?: CollectionUpdateOneOptions): Promise>; + options(options?: WithTimeout<'collectionAdminTimeoutMs'>): Promise>; + replaceOne(filter: CollectionFilter, replacement: NoId, options?: CollectionReplaceOneOptions): Promise>; + updateMany(filter: CollectionFilter, update: CollectionUpdateFilter, options?: CollectionUpdateManyOptions): Promise>; + updateOne(filter: CollectionFilter, update: CollectionUpdateFilter, options?: CollectionUpdateOneOptions): Promise>; +} + +// @public +export interface CollectionArrayFilterOps { + $all?: Elem; + $size?: number; +} + +// Warning: (ae-forgotten-export) The symbol "PickArrayTypes" needs to be exported by the entry point index.d.ts +// +// @public +export type CollectionArrayUpdate = { + [K in keyof Schema as any[] extends Schema[K] ? K : never]?: PickArrayTypes; +}; + +// @public +export type CollectionCurrentDate = { + [K in keyof Schema as Schema[K] extends Date | { + $date: number; + } ? K : never]?: boolean; +}; + +// @public +export interface CollectionDateFilterOps { + $gt?: Date; + $gte?: Date; + $lt?: Date; + $lte?: Date; } +// Warning: (ae-forgotten-export) The symbol "ContainsDate" needs to be exported by the entry point index.d.ts +// +// @public +export type CollectionDateUpdate = { + [K in keyof Schema as ContainsDate extends true ? K : never]?: Date | { + $date: number; + }; +}; + // @public export interface CollectionDefaultIdOptions { type: 'uuid' | 'uuidv6' | 'uuidv7' | 'objectId'; } +// @public +export interface CollectionDefinition { + defaultId?: CollectionDefaultIdOptions; + indexing?: CollectionIndexingOptions; + vector?: CollectionVectorOptions; +} + // @public export class CollectionDeleteManyError extends CumulativeOperationError { name: string; @@ -336,27 +359,52 @@ export interface CollectionDeleteOneResult { } // @public -export interface CollectionFindOneAndDeleteOptions extends WithTimeout { - projection?: Projection; - sort?: Sort; -} +export type CollectionFilter = { + [K in keyof ToDotNotation>]?: CollectionFilterExpr>[K]>; +} & { + _id?: CollectionFilterExpr>; + $and?: CollectionFilter[]; + $or?: CollectionFilter[]; + $not?: CollectionFilter; +} & { + [key: string]: any; +}; // @public -export interface CollectionFindOneAndReplaceOptions extends WithTimeout { - projection?: Projection; - returnDocument?: 'before' | 'after'; - sort?: Sort; - upsert?: boolean; -} +export type CollectionFilterExpr = Elem | (CollectionFilterOps & { + [key: string]: any; +}); +// Warning: (ae-forgotten-export) The symbol "IsNum" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "EmptyObj" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "IsDate" needs to be exported by the entry point index.d.ts +// // @public -export interface CollectionFindOneAndUpdateOptions extends WithTimeout { - projection?: Projection; - returnDocument?: 'before' | 'after'; - sort?: Sort; - upsert?: boolean; +export type CollectionFilterOps = { + $eq?: Elem; + $ne?: Elem; + $in?: Elem[]; + $nin?: Elem[]; + $exists?: boolean; +} & (IsNum extends false ? EmptyObj : CollectionNumFilterOps) & (IsDate extends false ? EmptyObj : (CollectionDateFilterOps | Date)) & (any[] extends Elem ? CollectionArrayFilterOps : EmptyObj); + +// @public (undocumented) +export class CollectionFindCursor extends FindCursor { + // (undocumented) + get dataSource(): Collection; + // (undocumented) + filter(filter: CollectionFilter): FindCursor; } +// @public +export type CollectionFindOneAndDeleteOptions = GenericFindOneAndDeleteOptions; + +// @public +export type CollectionFindOneAndReplaceOptions = GenericFindOneAndReplaceOptions; + +// @public +export type CollectionFindOneAndUpdateOptions = GenericFindOneAndUpdateOptions; + // @public export type CollectionFindOneOptions = GenericFindOneOptions; @@ -393,12 +441,40 @@ export interface CollectionInsertOneResult { } // @public -export interface CollectionOptions { - defaultId?: CollectionDefaultIdOptions; - indexing?: CollectionIndexingOptions; - vector?: CollectionVectorOptions; +export type CollectionNumberUpdate = { + [K in keyof Schema as IsNum extends true ? K : never]?: number | bigint; +}; + +// @public +export interface CollectionNumFilterOps { + $gt?: number | bigint | BigNumber; + $gte?: number | bigint | BigNumber; + $lt?: number | bigint | BigNumber; + $lte?: number | bigint | BigNumber; } +// @public +export interface CollectionOptions extends WithKeyspace { + embeddingApiKey?: string | EmbeddingHeadersProvider | null; + logging?: DataAPILoggingConfig; + // (undocumented) + serdes?: CollectionSerDesConfig; + timeoutDefaults?: Partial; +} + +// @public +export type CollectionPop = { + [K in keyof CollectionArrayUpdate]?: number; +}; + +// @public +export type CollectionPush = { + [K in keyof CollectionArrayUpdate]?: (CollectionArrayUpdate[K] | { + $each: CollectionArrayUpdate[K][]; + $position?: number; + }); +}; + // @public export type CollectionReplaceOneOptions = GenericReplaceOneOptions; @@ -418,12 +494,23 @@ export interface CollectionSerDesConfig { } // @public -export interface CollectionSpawnOptions extends WithKeyspace { - defaultMaxTimeMS?: number | null; - embeddingApiKey?: string | EmbeddingHeadersProvider | null; - logging?: DataAPILoggingConfig; - // (undocumented) - serdes?: CollectionSerDesConfig; +export interface CollectionUpdateFilter { + $addToSet?: CollectionPush & SomeDoc; + $currentDate?: CollectionCurrentDate & Record; + $inc?: CollectionNumberUpdate & Record; + $max?: (CollectionNumberUpdate | CollectionDateUpdate) & Record; + $min?: (CollectionNumberUpdate | CollectionDateUpdate) & Record; + $mul?: StrictCollectionNumberUpdate & Record; + $pop?: CollectionPop & Record; + $push?: CollectionPush & SomeDoc; + $rename?: Record; + $set?: Partial & SomeDoc; + $setOnInsert?: Partial & SomeDoc; + $unset?: Record; } // @public @@ -449,12 +536,12 @@ export interface CollectionVectorOptions { dimension?: number; metric?: 'cosine' | 'euclidean' | 'dot_product'; service?: VectorizeServiceOptions; + sourceModel?: string; } // @public export type Cols = keyof Omit; -// Warning: (ae-forgotten-export) The symbol "EmptyObj" needs to be exported by the entry point index.d.ts // Warning: (ae-incompatible-release-tags) The symbol "Cols2Add" is marked as @public, but its signature references "Cols2CqlTypes" which is marked as @internal // // @public (undocumented) @@ -480,14 +567,24 @@ export abstract class CommandEvent extends DataAPIClientEvent { // Warning: (ae-forgotten-export) The symbol "DataAPIRequestInfo" needs to be exported by the entry point index.d.ts // // @internal - protected constructor(info: DataAPIRequestInfo); + protected constructor(name: string, info: DataAPIRequestInfo); readonly command: Record; readonly commandName: string; + // @internal (undocumented) + protected _desc(): string; readonly keyspace: string; readonly source?: string; readonly url: string; } +// @public +export type CommandEventMap = { + commandStarted: (event: CommandStartedEvent) => void; + commandSucceeded: (event: CommandSucceededEvent) => void; + commandFailed: (event: CommandFailedEvent) => void; + commandWarnings: (event: CommandWarningsEvent) => void; +}; + // @public export class CommandFailedEvent extends CommandEvent { // @internal @@ -504,7 +601,7 @@ export class CommandStartedEvent extends CommandEvent { constructor(info: DataAPIRequestInfo); // (undocumented) formatted(): string; - readonly timeout: number; + readonly timeout: Partial; } // @public @@ -526,136 +623,6 @@ export class CommandWarningsEvent extends CommandEvent { readonly warnings: DataAPIErrorDescriptor[]; } -// @public (undocumented) -export class CqlBlob { - // (undocumented) - [$SerializeForTable]: () => { - $binary: string; - }; - constructor(blob: CqlBlobLike, validate?: boolean); - // (undocumented) - asArrayBuffer(): ArrayBuffer; - // (undocumented) - asBase64(): string; - // (undocumented) - asBuffer(): Buffer; - // (undocumented) - get byteLength(): number; - // (undocumented) - static isBlobLike(blob: unknown): blob is CqlBlobLike; - // (undocumented) - raw(): Exclude; - // (undocumented) - toString(): string; -} - -// @public (undocumented) -export type CqlBlobLike = CqlBlob | ArrayBuffer | Buffer | string; - -// @public (undocumented) -export class CqlDate { - // (undocumented) - [$SerializeForTable]: () => string; - constructor(input?: string | Date | CqlDateComponents); - // (undocumented) - components(): CqlDateComponents; - // (undocumented) - toDate(base?: Date | CqlTime | CqlTimestamp): Date; - // (undocumented) - toString(): string; -} - -// @public (undocumented) -export interface CqlDateComponents { - // (undocumented) - date: number; - // (undocumented) - month: number; - // (undocumented) - year: number; -} - -// @public (undocumented) -export class CqlDuration { - // (undocumented) - [$SerializeForTable]: () => string; - constructor(input: string | Partial | [Date | CqlTimestamp, Date | CqlTimestamp]); - // (undocumented) - components(): CqlDurationComponents; - // (undocumented) - toDates(reference: Date | CqlTimestamp): [Date, Date]; - // (undocumented) - toString(): string; -} - -// @public (undocumented) -export interface CqlDurationComponents { - // (undocumented) - days: number; - // (undocumented) - months: number; - // (undocumented) - nanoseconds: number; -} - -// @public (undocumented) -export class CqlTime { - // (undocumented) - [$SerializeForTable]: () => string; - constructor(input?: string | Date | (CqlTimeComponents & { - nanoseconds?: number; - })); - // (undocumented) - components(): CqlTimeComponents; - // (undocumented) - toDate(base?: Date | CqlDate | CqlTimestamp): Date; - // (undocumented) - toString(): string; -} - -// @public (undocumented) -export interface CqlTimeComponents { - // (undocumented) - hours: number; - // (undocumented) - minutes: number; - // (undocumented) - nanoseconds: number; - // (undocumented) - seconds: number; -} - -// @public (undocumented) -export class CqlTimestamp { - // (undocumented) - [$SerializeForTable]: () => string; - constructor(input?: string | Date | Partial); - // (undocumented) - components(): CqlTimestampComponents; - // (undocumented) - toDate(): Date; - // (undocumented) - toString(): string; -} - -// @public (undocumented) -export interface CqlTimestampComponents { - // (undocumented) - date: number; - // (undocumented) - hours: number; - // (undocumented) - minutes: number; - // (undocumented) - month: number; - // (undocumented) - nanoseconds: number; - // (undocumented) - seconds: number; - // (undocumented) - year: number; -} - // Warning: (ae-forgotten-export) The symbol "CqlNonGenericType2TSTypeDict" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "CqlGenericType2TSTypeDict" needs to be exported by the entry point index.d.ts // @@ -663,12 +630,14 @@ export interface CqlTimestampComponents { export type CqlType2TSType = T extends keyof CqlNonGenericType2TSTypeDict ? CqlNonGenericType2TSTypeDict[T] : T extends keyof CqlGenericType2TSTypeDict ? CqlGenericType2TSTypeDict[T] : unknown; // @public -export type CreateAstraDatabaseOptions = AstraAdminBlockingOptions & { - dbOptions?: DbSpawnOptions; +export type CreateAstraDatabaseOptions = AstraAdminBlockingOptions & WithTimeout<'databaseAdminTimeoutMs'> & { + dbOptions?: DbOptions; }; // @public -export interface CreateCollectionOptions extends WithTimeout, CollectionOptions, CollectionSpawnOptions { +export interface CreateCollectionOptions extends CollectionDefinition, CollectionOptions { + // (undocumented) + timeout?: number | Pick, 'collectionAdminTimeoutMs'>; } // @public (undocumented) @@ -682,20 +651,8 @@ export interface CreateTableDefinition { readonly primaryKey: CreateTablePrimaryKeyDefinition; } -// @public (undocumented) -export interface CreateTableIndexOptions extends WithTimeout { - // (undocumented) - ascii?: boolean; - // (undocumented) - caseSensitive?: boolean; - // (undocumented) - ifNotExists?: boolean; - // (undocumented) - normalize?: boolean; -} - // @public -export interface CreateTableOptions extends WithTimeout, TableSpawnOptions { +export interface CreateTableOptions extends WithTimeout<'tableAdminTimeoutMs'>, TableOptions { // (undocumented) definition: Def; // (undocumented) @@ -705,16 +662,6 @@ export interface CreateTableOptions = { - [K in keyof Schema as Schema[K] extends Date | { - $date: number; - } ? K : never]?: boolean; -}; - // @public (undocumented) export class CursorError extends DataAPIError { constructor(message: string, cursor: FindCursor); @@ -746,59 +686,115 @@ export type CursorStatus = 'idle' | 'started' | 'closed'; export interface CustomHttpClientOptions { client: 'custom'; fetcher: Fetcher; - maxTimeMS?: number; } +// @public (undocumented) +export class DataAPIBlob { + // (undocumented) + [$SerializeForTable]: () => { + $binary: string; + }; + constructor(blob: DataAPIBlobLike, validate?: boolean); + // (undocumented) + asArrayBuffer(): ArrayBuffer; + // (undocumented) + asBase64(): string; + // (undocumented) + asBuffer(): Buffer; + // (undocumented) + get byteLength(): number; + // (undocumented) + static isBlobLike(value: unknown): value is DataAPIBlobLike; + // (undocumented) + raw(): Exclude; + // (undocumented) + toString(): string; +} + +// @public (undocumented) +export type DataAPIBlobLike = DataAPIBlob | ArrayBuffer | Buffer | { + $binary: string; +}; + // @public export class DataAPIClient extends DataAPIClientEventEmitterBase { [Symbol.asyncDispose]: () => Promise; constructor(options?: DataAPIClientOptions | nullish); constructor(token: string | TokenProvider | nullish, options?: DataAPIClientOptions | nullish); - admin(options?: AdminSpawnOptions): AstraAdmin; + admin(options?: AdminOptions): AstraAdmin; close(): Promise; - db(endpoint: string, options?: DbSpawnOptions): Db; + db(endpoint: string, options?: DbOptions): Db; } // @public export abstract class DataAPIClientEvent { - abstract formatted(): string; + // @internal + protected constructor(name: string); + formatted(): string; + // (undocumented) + static formattedPrefix(): string; + readonly name: string; } // @public -export const DataAPIClientEventEmitterBase: new () => TypedEmitter; +export const DataAPIClientEventEmitterBase: new () => TypedEmitter; // @public -export type DataAPIClientEvents = DataAPICommandEvents & AdminCommandEvents; +export type DataAPIClientEventMap = AdminCommandEventMap & CommandEventMap; // @public export interface DataAPIClientOptions { - adminOptions?: DefaultAdminSpawnOptions; + adminOptions?: RootAdminOptions; caller?: OneOrMany; - dbOptions?: DefaultDbSpawnOptions; + dbOptions?: RootDbOptions; environment?: DataAPIEnvironment; httpOptions?: DataAPIHttpOptions; logging?: DataAPILoggingConfig; + timeoutDefaults?: Partial; } // @public -export type DataAPICommandEvents = { - commandStarted: (event: CommandStartedEvent) => void; - commandSucceeded: (event: CommandSucceededEvent) => void; - commandFailed: (event: CommandFailedEvent) => void; - commandWarnings: (event: CommandWarningsEvent) => void; -}; +export interface DataAPICreateKeyspaceOptions extends WithTimeout<'keyspaceAdminTimeoutMs'> { + // (undocumented) + replication?: KeyspaceReplicationOptions; + // (undocumented) + updateDbKeyspace?: boolean; +} + +// @public (undocumented) +export class DataAPIDate { + // (undocumented) + [$SerializeForTable]: () => string; + constructor(input?: string | Date | DataAPIDateComponents); + // (undocumented) + components(): DataAPIDateComponents; + // (undocumented) + toDate(base?: Date | DataAPITime | DataAPITimestamp): Date; + // (undocumented) + toString(): string; +} + +// @public (undocumented) +export interface DataAPIDateComponents { + // (undocumented) + date: number; + // (undocumented) + month: number; + // (undocumented) + year: number; +} // @public export class DataAPIDbAdmin extends DbAdmin { // @internal - constructor(db: Db, httpClient: DataAPIHttpClient, rawAdminOpts?: AdminSpawnOptions); - createKeyspace(keyspace: string, options?: LocalCreateKeyspaceOptions): Promise; + constructor(db: Db, httpClient: DataAPIHttpClient, rawAdminOpts?: AdminOptions); + createKeyspace(keyspace: string, options?: DataAPICreateKeyspaceOptions): Promise; db(): Db; - dropKeyspace(keyspace: string, options?: AstraAdminBlockingOptions): Promise; - findEmbeddingProviders(options?: WithTimeout): Promise; + dropKeyspace(keyspace: string, options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise; + findEmbeddingProviders(options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise; // (undocumented) - get _httpClient(): DataAPIHttpClient; - listKeyspaces(options?: WithTimeout): Promise; + get _httpClient(): DataAPIHttpClient<"admin">; + listKeyspaces(options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise; } // @public (undocumented) @@ -818,6 +814,29 @@ export interface DataAPIDetailedErrorDescriptor { readonly rawResponse: RawDataAPIResponse; } +// @public (undocumented) +export class DataAPIDuration { + // (undocumented) + [$SerializeForTable]: () => string; + constructor(input: string | Partial | [Date | DataAPITimestamp, Date | DataAPITimestamp]); + // (undocumented) + components(): DataAPIDurationComponents; + // (undocumented) + toDates(reference: Date | DataAPITimestamp): [Date, Date]; + // (undocumented) + toString(): string; +} + +// @public (undocumented) +export interface DataAPIDurationComponents { + // (undocumented) + days: number; + // (undocumented) + months: number; + // (undocumented) + nanoseconds: number; +} + // @public export type DataAPIEnvironment = typeof DataAPIEnvironments[number]; @@ -858,8 +877,13 @@ export type DataAPIHttpOptions = DefaultHttpClientOptions | FetchHttpClientOptio // @public export type DataAPILoggingConfig = DataAPILoggingEvent | readonly (DataAPILoggingEvent | DataAPIExplicitLoggingConfig)[]; +// Warning: (ae-incompatible-release-tags) The symbol "DataAPILoggingDefaults" is marked as @public, but its signature references "NormalizedLoggingConfig" which is marked as @internal +// +// @public (undocumented) +export const DataAPILoggingDefaults: NormalizedLoggingConfig[]; + // @public -export type DataAPILoggingEvent = 'all' | keyof DataAPIClientEvents; +export type DataAPILoggingEvent = 'all' | keyof DataAPIClientEventMap; // @public export type DataAPILoggingOutput = 'event' | 'stdout' | 'stderr'; @@ -874,30 +898,94 @@ export class DataAPIResponseError extends DataAPIError { } // @public (undocumented) -export interface DataAPISerCtx { +export interface DataAPISerCtx { + // (undocumented) + mutatingInPlace: boolean; + // (undocumented) + rootObj: Schema; +} + +// @public (undocumented) +export class DataAPITime { + // (undocumented) + [$SerializeForTable]: () => string; + constructor(input?: string | Date | (DataAPITimeComponents & { + nanoseconds?: number; + })); + // (undocumented) + components(): DataAPITimeComponents; + // (undocumented) + toDate(base?: Date | DataAPIDate | DataAPITimestamp): Date; + // (undocumented) + toString(): string; +} + +// @public (undocumented) +export interface DataAPITimeComponents { + // (undocumented) + hours: number; + // (undocumented) + minutes: number; + // (undocumented) + nanoseconds: number; + // (undocumented) + seconds: number; +} + +// @public +export class DataAPITimeoutError extends DataAPIError { + // Warning: (ae-forgotten-export) The symbol "HTTPRequestInfo" needs to be exported by the entry point index.d.ts + // + // @internal + constructor(info: HTTPRequestInfo, types: TimedOutCategories); + // (undocumented) + static mk(info: HTTPRequestInfo, types: TimedOutCategories): DataAPITimeoutError; + // (undocumented) + readonly timedOutTypes: TimedOutCategories; + readonly timeout: Partial; +} + +// @public (undocumented) +export class DataAPITimestamp { // (undocumented) - mutatingInPlace: boolean; + [$SerializeForTable]: () => string; + constructor(input?: string | Date | Partial); // (undocumented) - rootObj: Schema; + components(): DataAPITimestampComponents; + // (undocumented) + toDate(): Date; + // (undocumented) + toString(): string; } -// @public -export class DataAPITimeoutError extends DataAPIError { - // @internal - constructor(timeout: number); - readonly timeout: number; +// @public (undocumented) +export interface DataAPITimestampComponents { + // (undocumented) + date: number; + // (undocumented) + hours: number; + // (undocumented) + minutes: number; + // (undocumented) + month: number; + // (undocumented) + nanoseconds: number; + // (undocumented) + seconds: number; + // (undocumented) + year: number; } // @public (undocumented) export class DataAPIVector { // (undocumented) - [$SerializeForCollection]: () => number[] | { + [$SerializeForCollection]: () => { $binary: string; - }; + } | number[]; // (undocumented) - [$SerializeForTable]: () => number[] | { + [$SerializeForTable]: () => { $binary: string; - }; + } | number[]; constructor(vector: DataAPIVectorLike, validate?: boolean); // (undocumented) asArray(): number[]; @@ -916,36 +1004,21 @@ export class DataAPIVector { } // @public (undocumented) -export type DataAPIVectorLike = number[] | string | Float32Array | DataAPIVector; - -// @public -export interface DateFilterOps { - $gt?: Date; - $gte?: Date; - $lt?: Date; - $lte?: Date; -} - -// Warning: (ae-forgotten-export) The symbol "ContainsDate" needs to be exported by the entry point index.d.ts -// -// @public -export type DateUpdate = { - [K in keyof Schema as ContainsDate extends true ? K : never]?: Date | { - $date: number; - }; -}; +export type DataAPIVectorLike = number[] | { + $binary: string; +} | Float32Array | DataAPIVector; // @public export class Db { // @internal - constructor(rootOpts: InternalRootClientOpts, endpoint: string, rawDbOpts: DbSpawnOptions | nullish); - admin(options?: AdminSpawnOptions & { + constructor(rootOpts: InternalRootClientOpts, endpoint: string, rawDbOpts: DbOptions | nullish); + admin(options?: AdminOptions & { environment?: 'astra'; }): AstraDbAdmin; - admin(options: AdminSpawnOptions & { + admin(options: AdminOptions & { environment: Exclude; }): DataAPIDbAdmin; - collection(name: string, options?: CollectionSpawnOptions): Collection; + collection(name: string, options?: CollectionOptions): Collection; command(command: Record, options?: RunCommandOptions): Promise; createCollection(name: string, options?: CreateCollectionOptions): Promise>; createTable(name: string, options: CreateTableOptions, Def>): Promise>>; @@ -953,16 +1026,12 @@ export class Db { dropCollection(name: string, options?: DropCollectionOptions): Promise; dropTable(name: string, options?: DropTableOptions): Promise; // (undocumented) - dropTableIndex(name: string, options?: WithTimeout): Promise; + dropTableIndex(name: string, options?: TableDropIndexOptions): Promise; // (undocumented) - get _httpClient(): DataAPIHttpClient; + get _httpClient(): DataAPIHttpClient<"normal">; get id(): string; - info(options?: WithTimeout): Promise; + info(options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise; get keyspace(): string; - // Warning: (ae-forgotten-export) The symbol "KeyspaceRef" needs to be exported by the entry point index.d.ts - // - // (undocumented) - readonly _keyspace: KeyspaceRef; listCollections(options: ListCollectionsOptions & { nameOnly: true; }): Promise; @@ -976,39 +1045,40 @@ export class Db { nameOnly?: false; }): Promise; get region(): string; - table(name: string, options?: TableSpawnOptions): Table; + table(name: string, options?: TableOptions): Table; useKeyspace(keyspace: string): void; } // @public export abstract class DbAdmin { - abstract createKeyspace(keyspace: string, options?: AstraCreateKeyspaceOptions): Promise; + abstract createKeyspace(keyspace: string, options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise; abstract db(): Db; - abstract dropKeyspace(keyspace: string, options?: AstraAdminBlockingOptions): Promise; - abstract findEmbeddingProviders(options?: WithTimeout): Promise; - abstract listKeyspaces(): Promise; -} - -// @public -export interface DbSerDesConfig { - // (undocumented) - collection?: Omit, 'mutateInPlace'>; - mutateInPlace?: boolean; - // (undocumented) - table?: Omit, 'mutateInPlace'>; + abstract dropKeyspace(keyspace: string, options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise; + abstract findEmbeddingProviders(options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise; + abstract listKeyspaces(options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise; } // @public -export interface DbSpawnOptions { +export interface DbOptions { additionalHeaders?: Record; dataApiPath?: string; keyspace?: string | null; logging?: DataAPILoggingConfig; // (undocumented) serdes?: DbSerDesConfig; + timeoutDefaults?: Partial; token?: string | TokenProvider | null; } +// @public +export interface DbSerDesConfig { + // (undocumented) + collection?: Omit, 'mutateInPlace'>; + mutateInPlace?: boolean; + // (undocumented) + table?: Omit, 'mutateInPlace'>; +} + // @public export type DeepPartial = T extends object ? { [P in keyof T]?: DeepPartial; @@ -1017,18 +1087,11 @@ export type DeepPartial = T extends object ? { // @public export const DEFAULT_KEYSPACE = "default_keyspace"; -// @public (undocumented) -export type DefaultAdminSpawnOptions = Omit; - -// @public (undocumented) -export type DefaultDbSpawnOptions = Omit; - // @public export interface DefaultHttpClientOptions { client?: 'default'; fetchH2?: unknown; http1?: Http1Options; - maxTimeMS?: number; preferHttp2?: boolean; } @@ -1045,7 +1108,7 @@ export interface DevOpsAPIErrorDescriptor { // @public export class DevOpsAPIResponseError extends DevOpsAPIError { // @internal - constructor(resp: FetcherResponseInfo, data: Record | undefined); + constructor(resp: FetcherResponseInfo, data: SomeDoc | undefined); readonly errors: DevOpsAPIErrorDescriptor[]; readonly raw: FetcherResponseInfo; readonly status: number; @@ -1054,21 +1117,28 @@ export class DevOpsAPIResponseError extends DevOpsAPIError { // @public export class DevOpsAPITimeoutError extends DevOpsAPIError { // @internal - constructor(url: string, timeout: number); - readonly timeout: number; + constructor(info: HTTPRequestInfo, types: TimedOutCategories); + // (undocumented) + static mk(info: HTTPRequestInfo, types: TimedOutCategories): DevOpsAPITimeoutError; + // (undocumented) + readonly timedOutTypes: TimedOutCategories; + readonly timeout: Partial; readonly url: string; } // @public export class DevOpsUnexpectedStateError extends DevOpsAPIError { // @internal - constructor(message: string, expected: string[], data: Record | undefined); + constructor(message: string, expected: string[], data: SomeDoc | undefined); readonly dbInfo?: Record; readonly expected: string[]; } // @public -export interface DropCollectionOptions extends WithTimeout, WithKeyspace { +export type DropAstraDatabaseOptions = AstraAdminBlockingOptions & WithTimeout<'databaseAdminTimeoutMs'>; + +// @public +export interface DropCollectionOptions extends WithTimeout<'collectionAdminTimeoutMs'>, WithKeyspace { } // @public (undocumented) @@ -1078,7 +1148,9 @@ export interface DropColumnOperation { } // @public (undocumented) -export interface DropTableOptions extends WithTimeout, WithKeyspace { +export interface DropTableOptions extends WithTimeout<'tableAdminTimeoutMs'>, WithKeyspace { + // (undocumented) + ifExists?: boolean; } // @public (undocumented) @@ -1144,11 +1216,6 @@ export interface EmbeddingProviderTokenInfo { forwarded: string; } -// Warning: (ae-incompatible-release-tags) The symbol "EventLoggingDefaults" is marked as @public, but its signature references "NormalizedLoggingConfig" which is marked as @internal -// -// @public (undocumented) -export const EventLoggingDefaults: NormalizedLoggingConfig[]; - // @public export class FailedToLoadDefaultClientError extends Error { // @internal @@ -1194,7 +1261,6 @@ export class FetchH2 implements Fetcher { // @public export interface FetchHttpClientOptions { client: 'fetch'; - maxTimeMS?: number; } // @public @@ -1203,52 +1269,28 @@ export class FetchNative implements Fetcher { fetch(info: FetcherRequestInfo): Promise; } -// @public -export type Filter = { - [K in keyof NoId]?: FilterExpr[K]>; -} & { - _id?: FilterExpr>; - $and?: Filter[]; - $or?: Filter[]; - $not?: Filter; -} & { - [key: string]: any; -}; - -// @public -export type FilterExpr = Elem | FilterOps; - -// Warning: (ae-forgotten-export) The symbol "IsNum" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "IsDate" needs to be exported by the entry point index.d.ts -// -// @public -export type FilterOps = { - $eq?: Elem; - $ne?: Elem; - $in?: Elem[]; - $nin?: Elem[]; - $exists?: boolean; -} & (IsNum extends false ? EmptyObj : NumFilterOps) & (IsDate extends false ? EmptyObj : (DateFilterOps | Date)) & (any[] extends Elem ? ArrayFilterOps : EmptyObj); +// @public (undocumented) +export type Filter = Record; // @public -export class FindCursor { +export abstract class FindCursor { [Symbol.asyncIterator](): AsyncGenerator; // Warning: (ae-forgotten-export) The symbol "DataAPISerDes" needs to be exported by the entry point index.d.ts // // @internal - constructor(keyspace: string, parent: string, httpClient: DataAPIHttpClient, serdes: DataAPISerDes, filter: [Filter, boolean], options?: GenericFindOptions, mapping?: (doc: TRaw) => T); + constructor(parent: Table | Collection, serdes: DataAPISerDes, filter: [Filter, boolean], options?: GenericFindOptions, mapping?: (doc: TRaw) => T); buffered(): number; clone(): FindCursor; close(): void; consumeBuffer(max?: number): TRaw[]; consumed(): number; - filter(filter: Filter): FindCursor; + get dataSource(): Table | Collection; + filter(filter: Filter): FindCursor; forEach(consumer: ((doc: T) => boolean) | ((doc: T) => void)): Promise; getSortVector(): Promise; hasNext(): Promise; includeSimilarity(includeSimilarity?: boolean): FindCursor; includeSortVector(includeSortVector?: boolean): FindCursor; - get keyspace(): string; limit(limit: number): FindCursor; map(mapping: (doc: T) => R): FindCursor; next(): Promise; @@ -1281,7 +1323,7 @@ export type FoundRow = Omit, '$similarity'> & { // @public export interface FullCollectionInfo { name: string; - options: CollectionOptions; + options: CollectionDefinition; } // @public (undocumented) @@ -1307,7 +1349,7 @@ export interface GenericDeleteManyResult { } // @public (undocumented) -export interface GenericDeleteOneOptions extends WithTimeout { +export interface GenericDeleteOneOptions extends WithTimeout<'generalMethodTimeoutMs'> { // (undocumented) sort?: Sort; } @@ -1318,40 +1360,30 @@ export interface GenericDeleteOneResult { deletedCount: 0 | 1; } -// @public (undocumented) -export interface GenericFindOneAndDeleteOptions extends WithTimeout { - // (undocumented) +// @public +export interface GenericFindOneAndDeleteOptions extends WithTimeout<'generalMethodTimeoutMs'> { projection?: Projection; - // (undocumented) sort?: Sort; } -// @public (undocumented) -export interface GenericFindOneAndReplaceOptions extends WithTimeout { - // (undocumented) +// @public +export interface GenericFindOneAndReplaceOptions extends WithTimeout<'generalMethodTimeoutMs'> { projection?: Projection; - // (undocumented) returnDocument?: 'before' | 'after'; - // (undocumented) sort?: Sort; - // (undocumented) upsert?: boolean; } -// @public (undocumented) -export interface GenericFindOneAndUpdateOptions extends WithTimeout { - // (undocumented) +// @public +export interface GenericFindOneAndUpdateOptions extends WithTimeout<'generalMethodTimeoutMs'> { projection?: Projection; - // (undocumented) returnDocument?: 'before' | 'after'; - // (undocumented) sort?: Sort; - // (undocumented) upsert?: boolean; } // @public (undocumented) -export interface GenericFindOneOptions extends WithTimeout { +export interface GenericFindOneOptions extends WithTimeout<'generalMethodTimeoutMs'> { // (undocumented) includeSimilarity?: boolean; // (undocumented) @@ -1361,7 +1393,7 @@ export interface GenericFindOneOptions extends WithTimeout { } // @public (undocumented) -export interface GenericFindOptions { +export interface GenericFindOptions extends WithTimeout<'generalMethodTimeoutMs'> { // (undocumented) includeSimilarity?: boolean; // (undocumented) @@ -1385,7 +1417,7 @@ export type GenericInsertManyDocumentResponse<_T> = any; export type GenericInsertManyOptions = GenericInsertManyUnorderedOptions | GenericInsertManyOrderedOptions; // @public -export interface GenericInsertManyOrderedOptions extends WithTimeout { +export interface GenericInsertManyOrderedOptions extends WithTimeout<'generalMethodTimeoutMs'> { chunkSize?: number; ordered: true; } @@ -1401,7 +1433,7 @@ export interface GenericInsertManyResult { } // @public -export interface GenericInsertManyUnorderedOptions extends WithTimeout { +export interface GenericInsertManyUnorderedOptions extends WithTimeout<'generalMethodTimeoutMs'> { chunkSize?: number; concurrency?: number; ordered?: false; @@ -1424,7 +1456,7 @@ export interface GenericModifyResult { } // @public (undocumented) -export interface GenericReplaceOneOptions extends WithTimeout { +export interface GenericReplaceOneOptions extends WithTimeout<'generalMethodTimeoutMs'> { // (undocumented) sort?: Sort; // (undocumented) @@ -1432,13 +1464,13 @@ export interface GenericReplaceOneOptions extends WithTimeout { } // @public (undocumented) -export interface GenericUpdateManyOptions extends WithTimeout { +export interface GenericUpdateManyOptions extends WithTimeout<'generalMethodTimeoutMs'> { // (undocumented) upsert?: boolean; } // @public -export interface GenericUpdateOneOptions extends WithTimeout { +export interface GenericUpdateOneOptions extends WithTimeout<'generalMethodTimeoutMs'> { sort?: Sort; upsert?: boolean; } @@ -1516,7 +1548,7 @@ export type KeyspaceReplicationOptions = { }; // @public -export interface ListAstraDatabasesOptions extends WithTimeout { +export interface ListAstraDatabasesOptions extends WithTimeout<'databaseAdminTimeoutMs'> { include?: AstraDbStatusFilter; limit?: number; provider?: AstraDbCloudProviderFilter; @@ -1524,7 +1556,7 @@ export interface ListAstraDatabasesOptions extends WithTimeout { } // @public -export interface ListCollectionsOptions extends WithTimeout, WithKeyspace { +export interface ListCollectionsOptions extends WithTimeout<'collectionAdminTimeoutMs'>, WithKeyspace { nameOnly?: boolean; } @@ -1554,7 +1586,7 @@ export type ListTableKnownColumnDefinition = StrictCreateTableColumnDefinition; export type ListTablePrimaryKeyDefinition = Required; // @public (undocumented) -export interface ListTablesOptions extends WithTimeout, WithKeyspace { +export interface ListTablesOptions extends WithTimeout<'tableAdminTimeoutMs'>, WithKeyspace { // (undocumented) nameOnly?: boolean; } @@ -1579,14 +1611,6 @@ export interface ListTableUnsupportedColumnDefinition { type: 'UNSUPPORTED'; } -// @public -export interface LocalCreateKeyspaceOptions extends WithTimeout { - // (undocumented) - replication?: KeyspaceReplicationOptions; - // (undocumented) - updateDbKeyspace?: boolean; -} - // @public (undocumented) export type LooseCreateTableColumnDefinition = TableScalarType | string; @@ -1632,19 +1656,6 @@ export interface NoUpsertUpdateResult { // @public export type nullish = null | undefined; -// @public -export type NumberUpdate = { - [K in keyof Schema as IsNum extends true ? K : never]?: number | bigint; -}; - -// @public -export interface NumFilterOps { - $gt?: number | bigint; - $gte?: number | bigint; - $lt?: number | bigint; - $lte?: number | bigint; -} - // @public export class ObjectId { // (undocumented) @@ -1661,26 +1672,13 @@ export class ObjectId { export type OneOrMany = T | readonly T[]; // @public -export type Pop = { - [K in keyof ArrayUpdate]?: number; -}; - -// @public -export type Projection = Record; +export type Projection = Record; // @public export interface ProjectionSlice { $slice: number | [number, number]; } -// @public -export type Push = { - [K in keyof ArrayUpdate]?: (ArrayUpdate[K] | { - $each: ArrayUpdate[K][]; - $position?: number; - }); -}; - // @public export interface RawDataAPIResponse { data?: Record; @@ -1688,6 +1686,12 @@ export interface RawDataAPIResponse { status?: Record; } +// @public (undocumented) +export type RootAdminOptions = Omit; + +// @public (undocumented) +export type RootDbOptions = Omit; + // @public export interface Row { // (undocumented) @@ -1697,7 +1701,7 @@ export interface Row { } // @public -export interface RunCommandOptions extends WithTimeout { +export interface RunCommandOptions extends WithTimeout<'generalMethodTimeoutMs'> { collection?: string; keyspace?: string | null; // (undocumented) @@ -1734,14 +1738,10 @@ export type SomeRow = Record; export type SomeTableKey = Record; // @public -export type Sort = Record | { - $vector: number[]; -} | { - $vectorize: string; -}; +export type Sort = Record; // @public -export type SortDirection = 1 | -1 | 'asc' | 'desc' | 'ascending' | 'descending'; +export type SortDirection = 1 | -1; // @public export class StaticTokenProvider extends TokenProvider { @@ -1749,132 +1749,160 @@ export class StaticTokenProvider extends TokenProvider { getToken(): string | nullish; } -// @public (undocumented) -export type StrictCreateTableColumnDefinition = ScalarCreateTableColumnDefinition | MapCreateTableColumnDefinition | ListCreateTableColumnDefinition | SetCreateTableColumnDefinition | VectorCreateTableColumnDefinition; - // Warning: (ae-forgotten-export) The symbol "TypeErr" needs to be exported by the entry point index.d.ts // // @public -export type StrictDateUpdate> = ContainsDate extends true ? { +export type StrictCollectionDateUpdate> = ContainsDate extends true ? { [K in keyof InNotation as ContainsDate extends true ? K : never]?: Date | { $date: number; }; } : TypeErr<'Can not perform a date operation on a schema with no dates'>; // @public -export type StrictFilter = { - [K in keyof ToDotNotation>]?: FilterExpr>[K]>; +export type StrictCollectionFilter = { + [K in keyof ToDotNotation>]?: StrictCollectionFilterExpr>[K]>; } & { - _id?: FilterExpr>; - $and?: StrictFilter[]; - $or?: StrictFilter[]; - $not?: StrictFilter; + _id?: StrictCollectionFilterExpr>; + $and?: StrictCollectionFilter[]; + $or?: StrictCollectionFilter[]; + $not?: StrictCollectionFilter; }; +// @public +export type StrictCollectionFilterExpr = Elem | CollectionFilterOps; + // Warning: (ae-forgotten-export) The symbol "ContainsNum" needs to be exported by the entry point index.d.ts // // @public -export type StrictNumberUpdate> = ContainsNum extends true ? { +export type StrictCollectionNumberUpdate> = ContainsNum extends true ? { [K in keyof InNotation as IsNum extends true ? K : never]?: number | bigint; } : TypeErr<'Can not perform a number operation on a schema with no numbers'>; // Warning: (ae-forgotten-export) The symbol "ContainsArr" needs to be exported by the entry point index.d.ts // // @public -export type StrictPop> = ContainsArr extends true ? { - [K in keyof ArrayUpdate]?: number; +export type StrictCollectionPop> = ContainsArr extends true ? { + [K in keyof CollectionArrayUpdate]?: number; } : TypeErr<'Can not pop on a schema with no arrays'>; // @public -export type StrictProjection = { - [K in keyof ToDotNotation>]?: any[] extends (ToDotNotation>)[K] ? 1 | 0 | true | false | ProjectionSlice : 1 | 0 | true | false; -} & { - '*'?: 1 | 0 | true | false; -}; - -// @public -export type StrictPush> = ContainsArr extends true ? { - [K in keyof ArrayUpdate]?: (ArrayUpdate[K] | { - $each: ArrayUpdate[K][]; +export type StrictCollectionPush> = ContainsArr extends true ? { + [K in keyof CollectionArrayUpdate]?: (CollectionArrayUpdate[K] | { + $each: CollectionArrayUpdate[K][]; $position?: number; }); } : TypeErr<'Can not perform array operation on a schema with no arrays'>; // @public -export type StrictRename = { +export type StrictCollectionRename = { [K in keyof ToDotNotation]?: string; }; // @public -export type StrictSort = { - [K in keyof ToDotNotation>]?: SortDirection; -} | { - $vector: number[]; -} | { - $vectorize: string; -}; - -// @public -export type StrictUnset = { +export type StrictCollectionUnset = { [K in keyof ToDotNotation]?: '' | true | 1; }; // @public -export interface StrictUpdateFilter { - $addToSet?: StrictPush; - $currentDate?: CurrentDate>; - $inc?: StrictNumberUpdate; - $max?: StrictNumberUpdate | StrictDateUpdate; - $min?: StrictNumberUpdate | StrictDateUpdate; - $mul?: StrictNumberUpdate; - $pop?: StrictPop; - $push?: StrictPush; - $rename?: StrictRename; +export interface StrictCollectionUpdateFilter { + $addToSet?: StrictCollectionPush; + $currentDate?: CollectionCurrentDate>; + $inc?: StrictCollectionNumberUpdate; + $max?: StrictCollectionNumberUpdate | StrictCollectionDateUpdate; + $min?: StrictCollectionNumberUpdate | StrictCollectionDateUpdate; + $mul?: StrictCollectionNumberUpdate; + $pop?: StrictCollectionPop; + $push?: StrictCollectionPush; + $rename?: StrictCollectionRename; $set?: Partial>; $setOnInsert?: Partial>; - $unset?: StrictUnset; + $unset?: StrictCollectionUnset; } +// @public (undocumented) +export type StrictCreateTableColumnDefinition = ScalarCreateTableColumnDefinition | MapCreateTableColumnDefinition | ListCreateTableColumnDefinition | SetCreateTableColumnDefinition | VectorCreateTableColumnDefinition; + +// @public +export type StrictProjection = { + [K in keyof ToDotNotation>]?: any[] extends (ToDotNotation>)[K] ? 1 | 0 | true | false | ProjectionSlice : 1 | 0 | true | false; +} & { + '*'?: 1 | 0 | true | false; +}; + +// @public +export type StrictSort = { + [K in keyof ToDotNotation>]?: SortDirection; +} | { + $vector: number[]; +} | { + $vectorize: string; +}; + // @public export class Table { // @internal - constructor(db: Db, httpClient: DataAPIHttpClient, name: string, opts: TableSpawnOptions | undefined); + constructor(db: Db, httpClient: DataAPIHttpClient, name: string, opts: TableOptions | undefined); // (undocumented) alter>(options: Spec): Promise>>; // (undocumented) alter(options: AlterTableOptions): Promise>; // (undocumented) - countRows(filter: Filter, upperBound: number, options?: WithTimeout): Promise; + createIndex(name: string, column: Cols | string, options?: TableCreateIndexOptions): Promise; // (undocumented) - createIndex(name: string, column: Cols | string, options?: CreateTableIndexOptions): Promise; + createVectorIndex(name: string, column: Cols | string, options?: TableCreateVectorIndexOptions): Promise; // (undocumented) - createVectorIndex(name: string, column: Cols | string, options?: CreateTableVectorIndexOptions): Promise; + definition(options?: WithTimeout<'tableAdminTimeoutMs'>): Promise; // (undocumented) - definition(options?: WithTimeout): Promise; + deleteMany(filter: TableFilter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise; // (undocumented) - deleteMany(filter: Filter, options?: WithTimeout): Promise; + deleteOne(filter: TableFilter, options?: TableDeleteOneOptions): Promise; // (undocumented) - deleteOne(filter: Filter, options?: TableDeleteOneOptions): Promise; + drop(options?: WithTimeout<'tableAdminTimeoutMs'>): Promise; // (undocumented) - drop(options?: WithTimeout): Promise; + find(filter: TableFilter, options?: TableFindOptions & { + projection?: never; + }): TableFindCursor, FoundRow>; // (undocumented) - find(filter: Filter, options?: TableFindOptions): FindCursor, FoundRow>; + find>(filter: TableFilter, options: TableFindOptions): TableFindCursor, FoundRow>; // (undocumented) - findOne(filter: Filter, options?: TableFindOneOptions): Promise | null>; + findOne(filter: TableFilter, options?: TableFindOneOptions): Promise | null>; // (undocumented) - get _httpClient(): DataAPIHttpClient; + get _httpClient(): DataAPIHttpClient<"normal">; // (undocumented) - insertMany(document: Schema[], options?: TableInsertManyOptions): Promise>; - insertOne(row: Schema, options?: WithTimeout): Promise>; + insertMany(document: readonly Schema[], options?: TableInsertManyOptions): Promise>; + insertOne(row: Schema, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise>; readonly keyspace: string; readonly name: string; // (undocumented) - updateOne(filter: Filter, update: UpdateFilter, options?: TableUpdateOneOptions): Promise; + updateOne(filter: TableFilter, update: TableUpdateFilter, options?: TableUpdateOneOptions): Promise; } // @public (undocumented) export type TableColumnTypeParser = (val: any, ctx: TableDesCtx, definition: SomeDoc) => any; +// @public (undocumented) +export interface TableCreateIndexOptions extends WithTimeout<'tableAdminTimeoutMs'> { + // (undocumented) + ifNotExists?: boolean; + // (undocumented) + options?: { + caseSensitive?: boolean; + normalize?: boolean; + ascii?: boolean; + }; +} + +// @public (undocumented) +export interface TableCreateVectorIndexOptions extends WithTimeout<'tableAdminTimeoutMs'> { + // (undocumented) + ifNotExists?: boolean; + // (undocumented) + options?: { + metric: 'cosine' | 'euclidean' | 'dot_product'; + sourceModel?: string; + }; +} + // @public (undocumented) export type TableDeleteOneOptions = GenericDeleteOneOptions; @@ -1885,11 +1913,53 @@ export interface TableDesCtx extends DataAPIDesCtx { // (undocumented) parsingPrimaryKey: boolean; // (undocumented) - sparseData: boolean; + populateSparseData: boolean; // (undocumented) tableSchema: ListTableColumnDefinitions; } +// @public (undocumented) +export interface TableDropIndexOptions extends WithTimeout<'tableAdminTimeoutMs'> { + // (undocumented) + ifExists?: boolean; +} + +// @public +export type TableFilter = { + [K in keyof Schema]?: TableFilterExpr; +} & { + $and?: TableFilter[]; + $or?: TableFilter[]; + $not?: TableFilter; +} & { + [key: string]: any; +}; + +// @public +export type TableFilterExpr = Elem | TableFilterOps; + +// @public +export type TableFilterOps = { + $eq?: Elem; + $ne?: Elem; + $in?: Elem[]; + $nin?: Elem[]; + $exists?: boolean; + $lt?: Elem; + $lte?: Elem; + $gt?: Elem; + $gte?: Elem; + [key: string]: any; +}; + +// @public (undocumented) +export class TableFindCursor extends FindCursor { + // (undocumented) + get dataSource(): Table; + // (undocumented) + filter(filter: TableFilter): FindCursor; +} + // @public (undocumented) export type TableFindOneOptions = GenericFindOneOptions; @@ -1917,6 +1987,15 @@ export interface TableInsertOneResult { insertedId: KeyOf; } +// @public +export interface TableOptions extends WithKeyspace { + embeddingApiKey?: string | EmbeddingHeadersProvider | null; + logging?: DataAPILoggingConfig; + // (undocumented) + serdes?: TableSerDesConfig; + timeoutDefaults?: Partial; +} + // @public (undocumented) export type TableScalarType = 'ascii' | 'bigint' | 'blob' | 'boolean' | 'date' | 'decimal' | 'double' | 'duration' | 'float' | 'int' | 'inet' | 'smallint' | 'text' | 'time' | 'timestamp' | 'tinyint' | 'uuid' | 'varint'; @@ -1941,12 +2020,9 @@ export interface TableSerDesConfig { } // @public -export interface TableSpawnOptions extends WithKeyspace { - defaultMaxTimeMS?: number | null; - embeddingApiKey?: string | EmbeddingHeadersProvider | null; - logging?: DataAPILoggingConfig; - // (undocumented) - serdes?: TableSerDesConfig; +export interface TableUpdateFilter { + $set?: Partial & SomeRow; + $unset?: Record; } // @public @@ -1958,6 +2034,19 @@ export type TableUpdateManyResult = GenericUpdateResult< // @public export type TableUpdateOneOptions = GenericUpdateOneOptions; +// @public +export type TimedOutCategories = OneOrMany | 'provided'; + +// @public +export interface TimeoutDescriptor { + collectionAdminTimeoutMs: number; + databaseAdminTimeoutMs: number; + generalMethodTimeoutMs: number; + keyspaceAdminTimeoutMs: number; + requestTimeoutMs: number; + tableAdminTimeoutMs: number; +} + // Warning: (ae-forgotten-export) The symbol "Merge" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "_ToDotNotation" needs to be exported by the entry point index.d.ts // @@ -1987,25 +2076,8 @@ export class TooManyRowsToCountError extends DataAPIError { readonly limit: number; } -// @public -export interface UpdateFilter { - $addToSet?: Push & SomeDoc; - $currentDate?: CurrentDate & Record; - $inc?: NumberUpdate & Record; - $max?: (NumberUpdate | DateUpdate) & Record; - $min?: (NumberUpdate | DateUpdate) & Record; - $mul?: StrictNumberUpdate & Record; - $pop?: Pop & Record; - $push?: Push & SomeDoc; - $rename?: Record; - $set?: Partial & SomeDoc; - $setOnInsert?: Partial & SomeDoc; - $unset?: Record; -} +// @public (undocumented) +export type UpdateFilter = Record; // @public export interface UpsertedUpdateResult { @@ -2075,8 +2147,8 @@ export interface WithKeyspace { } // @public -export interface WithTimeout { - maxTimeMS?: number; +export interface WithTimeout { + timeout?: number | Pick, 'requestTimeoutMs' | Timeouts>; } // (No @packageDocumentation comment for this package) diff --git a/scripts/repl.sh b/scripts/repl.sh index 6891605d..8d71ff68 100755 --- a/scripts/repl.sh +++ b/scripts/repl.sh @@ -17,7 +17,7 @@ sh scripts/build.sh -light || exit 2 while [ $# -gt 0 ]; do case "$1" in "-local") - export CLIENT_DB_ENVIRONMENT='dse' + export CLIENT_DB_ENVIRONMENT='hcd' export CLIENT_DB_TOKEN='Cassandra:Y2Fzc2FuZHJh:Y2Fzc2FuZHJh' export CLIENT_DB_URL='http://localhost:8181' ;; diff --git a/src/administration/astra-admin.ts b/src/administration/astra-admin.ts index 3f35f7d8..dafe523c 100644 --- a/src/administration/astra-admin.ts +++ b/src/administration/astra-admin.ts @@ -29,7 +29,7 @@ import { parseAdminSpawnOpts } from '@/src/client/parsers/spawn-admin'; import { InternalRootClientOpts } from '@/src/client/types/internal'; import { buildAstraEndpoint } from '@/src/lib/utils'; import { Logger } from '@/src/lib/logging/logger'; -import { AdminSpawnOptions, DbSpawnOptions } from '@/src/client'; +import { AdminOptions, DbOptions } from '@/src/client'; import { $CustomInspect } from '@/src/lib/constants'; import { SomeDoc } from '@/src/documents'; import { Timeouts } from '@/src/lib/api/timeouts'; @@ -71,7 +71,7 @@ export class AstraAdmin { * * @internal */ - constructor(rootOpts: InternalRootClientOpts, rawAdminOpts?: AdminSpawnOptions) { + constructor(rootOpts: InternalRootClientOpts, rawAdminOpts?: AdminOptions) { const adminOpts = parseAdminSpawnOpts(rawAdminOpts, 'options'); const token = TokenProvider.parseToken([adminOpts?.adminToken, rootOpts.adminOptions.adminToken], 'admin token'); @@ -142,7 +142,7 @@ export class AstraAdmin { * * @returns A new {@link Db} instance. */ - public db(endpoint: string, options?: DbSpawnOptions): Db; + public db(endpoint: string, options?: DbOptions): Db; /** * Spawns a new {@link Db} instance using a direct endpoint and given options. @@ -176,9 +176,9 @@ export class AstraAdmin { * * @returns A new {@link Db} instance. */ - public db(id: string, region: string, options?: DbSpawnOptions): Db; + public db(id: string, region: string, options?: DbOptions): Db; - public db(endpointOrId: string, regionOrOptions?: string | DbSpawnOptions, maybeOptions?: DbSpawnOptions): Db { + public db(endpointOrId: string, regionOrOptions?: string | DbOptions, maybeOptions?: DbOptions): Db { const dbOpts = (typeof regionOrOptions === 'string') ? maybeOptions : regionOrOptions; @@ -229,7 +229,7 @@ export class AstraAdmin { * * @returns A new {@link Db} instance. */ - public dbAdmin(endpoint: string, options?: DbSpawnOptions): AstraDbAdmin; + public dbAdmin(endpoint: string, options?: DbOptions): AstraDbAdmin; /** * Spawns a new {@link Db} instance using a direct endpoint and given options. @@ -266,9 +266,9 @@ export class AstraAdmin { * * @returns A new {@link Db} instance. */ - public dbAdmin(id: string, region: string, options?: DbSpawnOptions): AstraDbAdmin; + public dbAdmin(id: string, region: string, options?: DbOptions): AstraDbAdmin; - public dbAdmin(endpointOrId: string, regionOrOptions?: string | DbSpawnOptions, maybeOptions?: DbSpawnOptions): AstraDbAdmin { + public dbAdmin(endpointOrId: string, regionOrOptions?: string | DbOptions, maybeOptions?: DbOptions): AstraDbAdmin { /* @ts-expect-error - calls internal representation of method */ return this.db(endpointOrId, regionOrOptions, maybeOptions).admin(this.#defaultOpts.adminOptions); } @@ -291,6 +291,7 @@ export class AstraAdmin { const resp = await this.#httpClient.request({ method: HttpMethods.Get, path: `/databases/${id}`, + methodName: 'admin.dbInfo', }, tm); return buildAstraDatabaseAdminInfo(resp.data!, this.#environment); @@ -347,6 +348,7 @@ export class AstraAdmin { method: HttpMethods.Get, path: `/databases`, params: params, + methodName: 'admin.listDatabases', }, tm); return resp.data!.map((d: SomeDoc) => buildAstraDatabaseAdminInfo(d, this.#environment)); @@ -419,6 +421,7 @@ export class AstraAdmin { method: HttpMethods.Post, path: '/databases', data: definition, + methodName: 'admin.createDatabase', }, { id: (resp) => resp.headers.location, target: 'ACTIVE', @@ -466,6 +469,7 @@ export class AstraAdmin { await this.#httpClient.requestLongRunning({ method: HttpMethods.Post, path: `/databases/${id}/terminate`, + methodName: 'admin.dropDatabase', }, { id: id, target: 'TERMINATED', diff --git a/src/administration/astra-db-admin.ts b/src/administration/astra-db-admin.ts index 1d86932a..0444ef65 100644 --- a/src/administration/astra-db-admin.ts +++ b/src/administration/astra-db-admin.ts @@ -32,7 +32,8 @@ import { $CustomInspect } from '@/src/lib/constants'; import { AstraDbAdminInfo } from '@/src/administration/types/admin/database-info'; import { Logger } from '@/src/lib/logging/logger'; import { TimeoutManager, Timeouts } from '@/src/lib/api/timeouts'; -import { AdminSpawnOptions } from '@/src/client'; +import { AdminOptions } from '@/src/client'; +import { DataAPIHttpClient } from '@/src/lib/api/clients'; /** * An administrative class for managing Astra databases, including creating, listing, and deleting keyspaces. @@ -69,6 +70,7 @@ import { AdminSpawnOptions } from '@/src/client'; */ export class AstraDbAdmin extends DbAdmin { readonly #httpClient: DevOpsAPIHttpClient; + readonly #dataApiHttpClient: DataAPIHttpClient<'admin'>; readonly #db: Db; readonly #environment: 'dev' | 'test' | 'prod'; @@ -77,7 +79,7 @@ export class AstraDbAdmin extends DbAdmin { * * @internal */ - constructor(db: Db, rootOpts: InternalRootClientOpts, rawAdminOpts: AdminSpawnOptions | undefined, dbToken: TokenProvider | undefined, endpoint: string) { + constructor(db: Db, rootOpts: InternalRootClientOpts, rawAdminOpts: AdminOptions | undefined, dbToken: TokenProvider | undefined, endpoint: string) { super(); const adminOpts = parseAdminSpawnOpts(rawAdminOpts, 'options'); @@ -101,6 +103,7 @@ export class AstraDbAdmin extends DbAdmin { timeoutDefaults: Timeouts.merge(rootOpts.adminOptions.timeoutDefaults, adminOpts?.timeoutDefaults), }); + this.#dataApiHttpClient = db._httpClient.forDbAdmin(adminOpts); this.#db = db; Object.defineProperty(this, $CustomInspect, { @@ -155,8 +158,9 @@ export class AstraDbAdmin extends DbAdmin { * @returns The available embedding providers. */ public override async findEmbeddingProviders(options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise { - const resp = await this.#db._httpClient.executeCommand({ findEmbeddingProviders: {} }, { + const resp = await this.#dataApiHttpClient.executeCommand({ findEmbeddingProviders: {} }, { timeoutManager: this.#httpClient.tm.single('databaseAdminTimeoutMs', options), + methodName: 'dbAdmin.findEmbeddingProviders', keyspace: null, }); return resp.status as FindEmbeddingProvidersResult; @@ -179,7 +183,7 @@ export class AstraDbAdmin extends DbAdmin { */ public async info(options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise { const tm = this.#httpClient.tm.single('databaseAdminTimeoutMs', options); - return this.#info(tm); + return this.#info('dbAdmin.info', tm); } /** @@ -200,7 +204,7 @@ export class AstraDbAdmin extends DbAdmin { */ public override async listKeyspaces(options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise { const tm = this.#httpClient.tm.single('keyspaceAdminTimeoutMs', options); - return this.#info(tm).then(i => i.keyspaces); + return this.#info('dbAdmin.listKeyspaces', tm).then(i => i.keyspaces); } /** @@ -243,6 +247,7 @@ export class AstraDbAdmin extends DbAdmin { await this.#httpClient.requestLongRunning({ method: HttpMethods.Post, path: `/databases/${this.#db.id}/keyspaces/${keyspace}`, + methodName: 'dmAdmin.createKeyspace', }, { id: this.#db.id, target: 'ACTIVE', @@ -290,6 +295,7 @@ export class AstraDbAdmin extends DbAdmin { await this.#httpClient.requestLongRunning({ method: HttpMethods.Delete, path: `/databases/${this.#db.id}/keyspaces/${keyspace}`, + methodName: 'dbAdmin.dropKeyspace', }, { id: this.#db.id, target: 'ACTIVE', @@ -327,6 +333,7 @@ export class AstraDbAdmin extends DbAdmin { await this.#httpClient.requestLongRunning({ method: HttpMethods.Post, path: `/databases/${this.#db.id}/terminate`, + methodName: 'dbAdmin.drop', }, { id: this.#db.id, target: 'TERMINATED', @@ -341,10 +348,11 @@ export class AstraDbAdmin extends DbAdmin { return this.#httpClient; } - async #info(tm: TimeoutManager): Promise { + async #info(methodName: string, tm: TimeoutManager): Promise { const resp = await this.#httpClient.request({ method: HttpMethods.Get, path: `/databases/${this.#db.id}`, + methodName, }, tm); return buildAstraDatabaseAdminInfo(resp.data!, this.#environment); diff --git a/src/administration/data-api-db-admin.ts b/src/administration/data-api-db-admin.ts index 7d64de8d..1e4b89a0 100644 --- a/src/administration/data-api-db-admin.ts +++ b/src/administration/data-api-db-admin.ts @@ -13,7 +13,7 @@ // limitations under the License. // noinspection ExceptionCaughtLocallyJS -import { LocalCreateKeyspaceOptions } from '@/src/administration/types'; +import { DataAPICreateKeyspaceOptions } from '@/src/administration/types'; import { DbAdmin } from '@/src/administration/db-admin'; import type { WithTimeout } from '@/src/lib'; import { FindEmbeddingProvidersResult } from '@/src/administration/types/db-admin/find-embedding-providers'; @@ -21,7 +21,7 @@ import { DataAPIHttpClient } from '@/src/lib/api/clients/data-api-http-client'; import { Db } from '@/src/db'; import { parseAdminSpawnOpts } from '@/src/client/parsers/spawn-admin'; import { $CustomInspect } from '@/src/lib/constants'; -import { AdminSpawnOptions } from '@/src/client'; +import { AdminOptions } from '@/src/client'; /** * An administrative class for managing non-Astra databases, including creating, listing, and deleting keyspaces. @@ -57,7 +57,7 @@ import { AdminSpawnOptions } from '@/src/client'; * @public */ export class DataAPIDbAdmin extends DbAdmin { - readonly #httpClient: DataAPIHttpClient; + readonly #httpClient: DataAPIHttpClient<'admin'>; readonly #db: Db; /** @@ -65,7 +65,7 @@ export class DataAPIDbAdmin extends DbAdmin { * * @internal */ - constructor(db: Db, httpClient: DataAPIHttpClient, rawAdminOpts?: AdminSpawnOptions) { + constructor(db: Db, httpClient: DataAPIHttpClient, rawAdminOpts?: AdminOptions) { super(); const adminOpts = parseAdminSpawnOpts(rawAdminOpts, 'options'); this.#httpClient = httpClient.forDbAdmin(adminOpts); @@ -116,6 +116,7 @@ export class DataAPIDbAdmin extends DbAdmin { public override async findEmbeddingProviders(options?: WithTimeout<'databaseAdminTimeoutMs'>): Promise { const resp = await this.#httpClient.executeCommand({ findEmbeddingProviders: {} }, { timeoutManager: this.#httpClient.tm.single('databaseAdminTimeoutMs', options), + methodName: 'dbAdmin.findEmbeddingProviders', keyspace: null, }); return resp.status as FindEmbeddingProvidersResult; @@ -140,6 +141,7 @@ export class DataAPIDbAdmin extends DbAdmin { public override async listKeyspaces(options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise { const resp = await this.#httpClient.executeCommand({ findKeyspaces: {} }, { timeoutManager: this.#httpClient.tm.single('keyspaceAdminTimeoutMs', options), + methodName: 'dbAdmin.listKeyspaces', keyspace: null, }); return resp.status!.keyspaces; @@ -175,7 +177,7 @@ export class DataAPIDbAdmin extends DbAdmin { * * @returns A promise that resolves when the operation completes. */ - public override async createKeyspace(keyspace: string, options?: LocalCreateKeyspaceOptions): Promise { + public override async createKeyspace(keyspace: string, options?: DataAPICreateKeyspaceOptions): Promise { if (options?.updateDbKeyspace) { this.#db.useKeyspace(keyspace); } @@ -187,6 +189,7 @@ export class DataAPIDbAdmin extends DbAdmin { await this.#httpClient.executeCommand({ createKeyspace: { name: keyspace, options: { replication } } }, { timeoutManager: this.#httpClient.tm.single('keyspaceAdminTimeoutMs', options), + methodName: 'dbAdmin.createKeyspace', keyspace: null, }); } @@ -215,6 +218,7 @@ export class DataAPIDbAdmin extends DbAdmin { public override async dropKeyspace(keyspace: string, options?: WithTimeout<'keyspaceAdminTimeoutMs'>): Promise { await this.#httpClient.executeCommand({ dropKeyspace: { name: keyspace } }, { timeoutManager: this.#httpClient.tm.single('keyspaceAdminTimeoutMs', options), + methodName: 'dbAdmin.dropKeyspace', keyspace: null, }); } diff --git a/src/administration/events.ts b/src/administration/events.ts index db8c2169..03ac05b9 100644 --- a/src/administration/events.ts +++ b/src/administration/events.ts @@ -11,10 +11,10 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// import { DataAPIClientEvent } from '@/src/lib/logging/events'; needs to be like this or it errors import type { DevOpsAPIRequestInfo } from '@/src/lib/api/clients/devops-api-http-client'; import type { DataAPIErrorDescriptor } from '@/src/documents'; -// import { DataAPIClientEvent } from '@/src/lib/logging/events'; needs to be like this or it errors import { DataAPIClientEvent } from '@/src/lib/logging/events'; import { TimeoutDescriptor } from '@/src/lib/api/timeouts'; @@ -24,7 +24,7 @@ import { TimeoutDescriptor } from '@/src/lib/api/timeouts'; * * @public */ -export type AdminCommandEvents = { +export type AdminCommandEventMap = { /** * Emitted when an admin command is started, before the initial HTTP request is made. */ @@ -41,6 +41,9 @@ export type AdminCommandEvents = { * Emitted when an admin command has errored. */ adminCommandFailed: (event: AdminCommandFailedEvent) => void, + /** + * Emitted when an admin command has warnings. + */ adminCommandWarnings: (event: AdminCommandWarningsEvent) => void, } @@ -75,18 +78,32 @@ export abstract class AdminCommandEvent extends DataAPIClientEvent { */ public readonly longRunning: boolean; + /** + * The method which invoked the request + */ + public readonly methodName: string; + /** * Should not be instantiated directly. * * @internal */ - protected constructor(info: DevOpsAPIRequestInfo, longRunning: boolean) { - super(); + protected constructor(name: string, info: DevOpsAPIRequestInfo, longRunning: boolean) { + super(name); this.path = info.path; this.method = info.method; this.reqBody = info.data; this.params = info.params; this.longRunning = longRunning; + this.methodName = info.methodName; + } + + /** + * @internal + * @protected + */ + protected _desc() { + return `(${this.methodName}) ${this.method} ${this.path}${this.params ? '?' : ''}${new URLSearchParams(this.params).toString()}`; } } @@ -109,12 +126,12 @@ export class AdminCommandStartedEvent extends AdminCommandEvent { * @internal */ constructor(info: DevOpsAPIRequestInfo, longRunning: boolean, timeout: Partial) { - super(info, longRunning); + super('AdminCommandStarted', info, longRunning); this.timeout = timeout; } public formatted(): string { - return `[AdminCommandStartedEvent]: ${this.method} ${this.path}${this.params ? '?' : ''}${new URLSearchParams(this.params).toString()} ${this.longRunning ? '(blocking)' : ''} ${this.reqBody ? JSON.stringify(this.reqBody) : ''}`; + return `${super.formatted()}: ${this._desc()} ${this.longRunning ? '(blocking) ' : ' '}${this.reqBody ? JSON.stringify(this.reqBody) : ''}`; } } @@ -149,14 +166,14 @@ export class AdminCommandPollingEvent extends AdminCommandEvent { * @internal */ constructor(info: DevOpsAPIRequestInfo, started: number, interval: number, pollCount: number) { - super(info, true); + super('AdminCommandPolling', info, true); this.elapsed = performance.now() - started; this.interval = interval; this.pollCount = pollCount; } public formatted(): string { - return `[AdminCommandPollingEvent]: ${this.method} ${this.path}${this.params ? '?' : ''}${new URLSearchParams(this.params).toString()} (poll #${this.pollCount}; ${this.elapsed}ms elapsed)`; + return `${super.formatted()}: ${this._desc()} (poll #${this.pollCount}; ${~~this.elapsed}ms elapsed)`; } } @@ -184,13 +201,13 @@ export class AdminCommandSucceededEvent extends AdminCommandEvent { * @internal */ constructor(info: DevOpsAPIRequestInfo, longRunning: boolean, data: Record | undefined, started: number) { - super(info, longRunning); + super('AdminCommandSucceeded', info, longRunning); this.duration = performance.now() - started; this.resBody = data || undefined; } public formatted(): string { - return `[AdminCommandSucceededEvent]: ${this.method} ${this.path}${this.params ? '?' : ''}${new URLSearchParams(this.params).toString()}} ${this.reqBody ? JSON.stringify(this.reqBody) : ''} (took ${this.duration}ms)`; + return `${super.formatted()}: ${this._desc()} ${this.reqBody ? JSON.stringify(this.reqBody) + ' ' : ''}(took ${~~this.duration}ms)`; } } @@ -221,13 +238,13 @@ export class AdminCommandFailedEvent extends AdminCommandEvent { * @internal */ constructor(info: DevOpsAPIRequestInfo, longRunning: boolean, error: Error, started: number) { - super(info, longRunning); + super('AdminCommandFailed', info, longRunning); this.duration = performance.now() - started; this.error = error; } public formatted(): string { - return `[AdminCommandFailedEvent]: ${this.method} ${this.path}${this.params ? '?' : ''}${new URLSearchParams(this.params).toString()} ${this.reqBody ? JSON.stringify(this.reqBody) : ''} (took ${this.duration}ms) - '${this.error.message}'`; + return `${super.formatted()}: ${this._desc()} ${this.reqBody ? JSON.stringify(this.reqBody) + ' ' : ''}(took ${~~this.duration}ms) - '${this.error.message}'`; } } @@ -235,11 +252,11 @@ export class AdminCommandWarningsEvent extends AdminCommandEvent { public readonly warnings: DataAPIErrorDescriptor[]; constructor(info: DevOpsAPIRequestInfo, longRunning: boolean, warnings: DataAPIErrorDescriptor[]) { - super(info, longRunning); + super('AdminCommandWarnings', info, longRunning); this.warnings = warnings; } - formatted(): string { - return `[AdminCommandWarningsEvent]: ${this.method} ${this.path}${this.params ? '?' : ''}${new URLSearchParams(this.params).toString()} ${this.reqBody ? JSON.stringify(this.reqBody) : ''} - '${this.warnings.map(w => w.message).join(', ')}'`; + public formatted(): string { + return `${super.formatted()}: ${this._desc()} ${this.reqBody ? JSON.stringify(this.reqBody) + ' ' : ''}- '${this.warnings.map(w => w.message).join(', ')}'`; } } diff --git a/src/administration/types/admin/create-database.ts b/src/administration/types/admin/create-database.ts index 5c6f4a26..c49d227d 100644 --- a/src/administration/types/admin/create-database.ts +++ b/src/administration/types/admin/create-database.ts @@ -15,7 +15,7 @@ import { AstraAdminBlockingOptions, AstraDbCloudProvider } from '@/src/administration/types'; -import { DbSpawnOptions } from '@/src/client'; +import { DbOptions } from '@/src/client'; import { WithTimeout } from '@/src/lib'; /** @@ -55,5 +55,5 @@ export type CreateAstraDatabaseOptions = AstraAdminBlockingOptions & WithTimeout /** * Any options to override the default options set when creating the root {@link DataAPIClient}. */ - dbOptions?: DbSpawnOptions, + dbOptions?: DbOptions, } diff --git a/src/administration/types/db-admin/local-create-keyspace.ts b/src/administration/types/db-admin/local-create-keyspace.ts index 8759bbbc..c44d5711 100644 --- a/src/administration/types/db-admin/local-create-keyspace.ts +++ b/src/administration/types/db-admin/local-create-keyspace.ts @@ -42,7 +42,7 @@ import { WithTimeout } from '@/src/lib'; * * @public */ -export interface LocalCreateKeyspaceOptions extends WithTimeout<'keyspaceAdminTimeoutMs'> { +export interface DataAPICreateKeyspaceOptions extends WithTimeout<'keyspaceAdminTimeoutMs'> { replication?: KeyspaceReplicationOptions, updateDbKeyspace?: boolean, } diff --git a/src/administration/types/index.ts b/src/administration/types/index.ts index 9c4bee6d..34349450 100644 --- a/src/administration/types/index.ts +++ b/src/administration/types/index.ts @@ -52,7 +52,7 @@ export type { export type { KeyspaceReplicationOptions, - LocalCreateKeyspaceOptions, + DataAPICreateKeyspaceOptions, } from './db-admin/local-create-keyspace'; export type { diff --git a/src/client/data-api-client.ts b/src/client/data-api-client.ts index 1655d18f..4a12fd9e 100644 --- a/src/client/data-api-client.ts +++ b/src/client/data-api-client.ts @@ -15,15 +15,15 @@ import type TypedEmitter from 'typed-emitter'; import type { - AdminSpawnOptions, + AdminOptions, CustomHttpClientOptions, DataAPIClientOptions, - DbSpawnOptions, + DbOptions, DefaultHttpClientOptions, } from '@/src/client/types'; import { LIB_NAME } from '@/src/version'; import type { InternalRootClientOpts } from '@/src/client/types/internal'; -import { type DataAPIClientEvents, type Fetcher, FetchH2, FetchNative, type nullish, TokenProvider } from '@/src/lib'; +import { type DataAPIClientEventMap, type Fetcher, FetchH2, FetchNative, type nullish, TokenProvider } from '@/src/lib'; import { buildUserAgent } from '@/src/lib/api/clients/http-client'; import { Db, InvalidEnvironmentError } from '@/src/db'; import { AstraAdmin } from '@/src/administration'; @@ -48,7 +48,7 @@ import { Timeouts } from '@/src/lib/api/timeouts'; */ export const DataAPIClientEventEmitterBase = (() => { try { - return (require('events') as { EventEmitter: (new () => TypedEmitter) }).EventEmitter; + return (require('events') as { EventEmitter: (new () => TypedEmitter) }).EventEmitter; } catch (_) { throw new Error(`\`${LIB_NAME}\` requires the \`events\` module to be available for usage. Please provide a polyfill (e.g. the \`events\` package) or use a compatible environment.`); } @@ -221,7 +221,7 @@ export class DataAPIClient extends DataAPIClientEventEmitterBase { * * @returns A new {@link Db} instance. */ - public db(endpoint: string, options?: DbSpawnOptions): Db { + public db(endpoint: string, options?: DbOptions): Db { return new Db(this.#options, endpoint, options); } @@ -247,7 +247,7 @@ export class DataAPIClient extends DataAPIClientEventEmitterBase { * * @returns A new {@link AstraAdmin} instance. */ - public admin(options?: AdminSpawnOptions): AstraAdmin { + public admin(options?: AdminOptions): AstraAdmin { if (this.#options.environment !== 'astra') { throw new InvalidEnvironmentError('admin', this.#options.environment, ['astra'], 'AstraAdmin is only available for Astra databases'); } @@ -309,7 +309,7 @@ export class DataAPIClient extends DataAPIClientEventEmitterBase { public [Symbol.asyncDispose]!: () => Promise; } -function buildFetchCtx(options: DataAPIClientOptions | undefined): FetchCtx { +const buildFetchCtx = (options: DataAPIClientOptions | undefined): FetchCtx => { const clientType = (options?.httpOptions) ? options.httpOptions?.client ?? 'default' : undefined; @@ -325,9 +325,9 @@ function buildFetchCtx(options: DataAPIClientOptions | undefined): FetchCtx { ctx: ctx, closed: { ref: false }, }; -} +}; -function tryLoadFetchH2(clientType: string | nullish, options: DataAPIClientOptions | undefined): Fetcher { +const tryLoadFetchH2 = (clientType: string | nullish, options: DataAPIClientOptions | undefined): Fetcher => { try { const httpOptions = options?.httpOptions as DefaultHttpClientOptions | undefined; const preferHttp2 = httpOptions?.preferHttp2 ?? true; @@ -339,7 +339,7 @@ function tryLoadFetchH2(clientType: string | nullish, options: DataAPIClientOpti throw e; } } -} +}; const parseClientOpts: Parser = (raw, field) => { const opts = p.parse('object?')(raw, field); diff --git a/src/client/parsers/spawn-admin.ts b/src/client/parsers/spawn-admin.ts index 4e45fb93..4eb133a7 100644 --- a/src/client/parsers/spawn-admin.ts +++ b/src/client/parsers/spawn-admin.ts @@ -15,11 +15,11 @@ import { p, Parser } from '@/src/lib/validation'; import { TokenProvider } from '@/src/lib'; import { Logger } from '@/src/lib/logging/logger'; -import { AdminSpawnOptions } from '@/src/client'; +import { AdminOptions } from '@/src/client'; import { Timeouts } from '@/src/lib/api/timeouts'; -export const parseAdminSpawnOpts: Parser = (raw, field) => { - const opts = p.parse('object?')(raw, field); +export const parseAdminSpawnOpts: Parser = (raw, field) => { + const opts = p.parse('object?')(raw, field); if (!opts) { return undefined; diff --git a/src/client/parsers/spawn-db.ts b/src/client/parsers/spawn-db.ts index 6cd64785..226e5b1d 100644 --- a/src/client/parsers/spawn-db.ts +++ b/src/client/parsers/spawn-db.ts @@ -13,15 +13,15 @@ // limitations under the License. import { p, Parser } from '@/src/lib/validation'; -import { DbSerDesConfig, DbSpawnOptions } from '@/src/client'; +import { DbSerDesConfig, DbOptions } from '@/src/client'; import { TokenProvider } from '@/src/lib'; import { isNullish } from '@/src/lib/utils'; import { Logger } from '@/src/lib/logging/logger'; import { CollectionSerDesConfig, SomeDoc, TableColumnTypeParser, TableSerDesConfig } from '@/src/documents'; import { Timeouts } from '@/src/lib/api/timeouts'; -export const parseDbSpawnOpts: Parser = (raw, field) => { - const opts = p.parse('object?')(raw, field); +export const parseDbSpawnOpts: Parser = (raw, field) => { + const opts = p.parse('object?')(raw, field); if (!opts) { return undefined; diff --git a/src/client/types/client-opts.ts b/src/client/types/client-opts.ts index 50db7f27..5c1f5ea9 100644 --- a/src/client/types/client-opts.ts +++ b/src/client/types/client-opts.ts @@ -13,7 +13,7 @@ // limitations under the License. import type { DataAPIEnvironment, DataAPILoggingConfig, TimeoutDescriptor } from '@/src/lib'; -import type { Caller, DataAPIHttpOptions, DefaultAdminSpawnOptions, DefaultDbSpawnOptions } from '@/src/client'; +import type { Caller, DataAPIHttpOptions, RootAdminOptions, RootDbOptions } from '@/src/client'; import { OneOrMany } from '@/src/lib/types'; /** @@ -81,11 +81,11 @@ export interface DataAPIClientOptions { /** * The default options when spawning a {@link Db} instance. */ - dbOptions?: DefaultDbSpawnOptions, + dbOptions?: RootDbOptions, /** * The default options when spawning an {@link AstraAdmin} instance. */ - adminOptions?: DefaultAdminSpawnOptions, + adminOptions?: RootAdminOptions, /** * The caller information to send with requests, of the form `[name, version?]`, or an array of such. * diff --git a/src/client/types/internal.ts b/src/client/types/internal.ts index accc3aae..d55438f2 100644 --- a/src/client/types/internal.ts +++ b/src/client/types/internal.ts @@ -13,7 +13,7 @@ // limitations under the License. import type { - DataAPIClientEvents, + DataAPIClientEventMap, DataAPIEnvironment, DataAPILoggingOutput, TimeoutDescriptor, @@ -21,28 +21,28 @@ import type { } from '@/src/lib'; import type TypedEmitter from 'typed-emitter'; import type { FetchCtx } from '@/src/lib/api/fetch/types'; -import type { AdminSpawnOptions, DbSpawnOptions } from '@/src/client'; +import type { AdminOptions, DbOptions } from '@/src/client'; import type { NormalizedLoggingConfig } from '@/src/lib/logging/types'; /** * @internal */ -export type InternalLoggingConfig = Readonly> | undefined>> +export type InternalLoggingConfig = Readonly> | undefined>> /** * @internal */ export interface InternalRootClientOpts { environment: DataAPIEnvironment, - emitter: TypedEmitter, + emitter: TypedEmitter, fetchCtx: FetchCtx, userAgent: string, - dbOptions: Omit & { + dbOptions: Omit & { token: TokenProvider | undefined, logging: NormalizedLoggingConfig[] | undefined, timeoutDefaults: TimeoutDescriptor, }, - adminOptions: Omit & { + adminOptions: Omit & { adminToken: TokenProvider | undefined, logging: NormalizedLoggingConfig[] | undefined, timeoutDefaults: TimeoutDescriptor, diff --git a/src/client/types/spawn-admin.ts b/src/client/types/spawn-admin.ts index c51b8fb6..7230dc9c 100644 --- a/src/client/types/spawn-admin.ts +++ b/src/client/types/spawn-admin.ts @@ -14,7 +14,7 @@ import type { DataAPILoggingConfig, TimeoutDescriptor, TokenProvider } from '@/src/lib'; -export type DefaultAdminSpawnOptions = Omit; +export type RootAdminOptions = Omit; /** * The options available spawning a new {@link AstraAdmin} instance. @@ -25,7 +25,7 @@ export type DefaultAdminSpawnOptions = Omit; +export type RootDbOptions = Omit; /** * The options available spawning a new {@link Db} instance. @@ -24,7 +24,7 @@ export type DefaultDbSpawnOptions = Omit }): DataAPIDbAdmin + public admin(options: AdminOptions & { environment: Exclude }): DataAPIDbAdmin - public admin(options?: AdminSpawnOptions & { environment?: DataAPIEnvironment }): DbAdmin { + public admin(options?: AdminOptions & { environment?: DataAPIEnvironment }): DbAdmin { const environment = options?.environment ?? 'astra'; validateDataAPIEnv(environment); if (this.#defaultOpts.environment !== environment) { - throw new InvalidEnvironmentError('db.admin()', this.#defaultOpts.environment, [environment], 'environment option is not the same as set in the DataAPIClient'); + throw new InvalidEnvironmentError('db.admin()', environment, [this.#defaultOpts.environment], 'environment option is not the same as set in the DataAPIClient'); } if (environment === 'astra') { @@ -548,11 +546,10 @@ export class Db { * @see VectorizeDoc * @see db.createCollection */ - public collection(name: string, options?: CollectionSpawnOptions): Collection { + public collection(name: string, options?: CollectionOptions): Collection { return new Collection(this, this.#httpClient, name, { ...options, serdes: { - ...options?.serdes, serialize: [...toArray(options?.serdes?.serialize ?? []), ...toArray(this.#defaultOpts.dbOptions?.serdes?.collection?.serialize ?? [])], deserialize: [...toArray(options?.serdes?.deserialize ?? []), ...toArray(this.#defaultOpts.dbOptions?.serdes?.collection?.deserialize ?? [])], mutateInPlace: options?.serdes?.mutateInPlace ?? this.#defaultOpts.dbOptions.serdes?.mutateInPlace, @@ -606,11 +603,11 @@ export class Db { * * @example * ```ts - * import { CqlDate, UUID, Row, DataAPIVector, ... } from 'astra-db-ts'; + * import { DataAPIDate, UUID, Row, DataAPIVector, ... } from 'astra-db-ts'; * * interface User extends Row { *   id: string, // Partition key - *   dob: CqlDate, // Clustering (partition sort) key + *   dob: DataAPIDate, // Clustering (partition sort) key *   friends: Map, *   vector: DataAPIVector, * } @@ -620,7 +617,7 @@ export class Db { * // res.insertedId is of type { id: string } * const res = await table.insertOne({ *   id: '123', - *   dob: new CqlDate(new Date()), + *   dob: new DataAPIDate(new Date()), *   friends: new Map([['Alice', UUID.random()]]), *   vector: new DataAPIVector([1, 2, 3]), // Class enables encoding optimization * }); @@ -643,7 +640,7 @@ export class Db { * @see Row * @see $PrimaryKeyType */ - public table(name: string, options?: TableSpawnOptions): Table { + public table(name: string, options?: TableOptions): Table { return new Table(this, this.#httpClient, name, { ...options, serdes: { @@ -887,7 +884,7 @@ export class Db { * ```ts * interface User extends Row { *   name: string, - *   dob: CqlDate, + *   dob: DataAPIDate, *   friends?: Set, * } * @@ -1036,8 +1033,8 @@ export class Db { }); } - public async dropTableIndex(name: string, options?: WithTimeout<'tableAdminTimeoutMs'>): Promise { - await this.#httpClient.executeCommand({ dropIndex: { name } }, { + public async dropTableIndex(name: string, options?: TableDropIndexOptions): Promise { + await this.#httpClient.executeCommand({ dropIndex: { name, options: { ifExists: options?.ifExists } } }, { timeoutManager: this.#httpClient.tm.single('tableAdminTimeoutMs', options), }); } diff --git a/src/db/types/collections/collection-definition.ts b/src/db/types/collections/collection-definition.ts new file mode 100644 index 00000000..67bf1d27 --- /dev/null +++ b/src/db/types/collections/collection-definition.ts @@ -0,0 +1,40 @@ +// Copyright DataStax, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { SomeDoc } from '@/src/documents/collections'; +import { CollectionDefaultIdOptions, CollectionIndexingOptions, CollectionVectorOptions } from '@/src/db'; + +/** + * Represents the options for the createCollection command. + * + * @field vector - Options related to vector search. + * @field indexing - Options related to indexing. + * @field defaultId - Options related to the default ID. + * + * @public + */ +export interface CollectionDefinition { + /** + * Options related to vector search. + */ + vector?: CollectionVectorOptions, + /** + * Options related to indexing. + */ + indexing?: CollectionIndexingOptions, + /** + * Options related to the default ID. + */ + defaultId?: CollectionDefaultIdOptions, +} diff --git a/src/db/types/collections/collection-options.ts b/src/db/types/collections/collection-options.ts index ce80b230..70724294 100644 --- a/src/db/types/collections/collection-options.ts +++ b/src/db/types/collections/collection-options.ts @@ -12,29 +12,74 @@ // See the License for the specific language governing permissions and // limitations under the License. -import type { SomeDoc } from '@/src/documents/collections'; -import { CollectionDefaultIdOptions, CollectionIndexingOptions, CollectionVectorOptions } from '@/src/db'; +import { WithKeyspace } from '@/src/db'; +import { CollectionSerDesConfig, EmbeddingHeadersProvider, SomeDoc } from '@/src/documents'; +import { DataAPILoggingConfig, type TimeoutDescriptor } from '@/src/lib'; /** - * Represents the options for the createCollection command. + * Options for spawning a new `Collection` instance through {@link db.collection} or {@link db.createCollection}. * - * @field vector - Options related to vector search. - * @field indexing - Options related to indexing. - * @field defaultId - Options related to the default ID. + * Note that these are not all the options available for when you're actually creating a table—see {@link CreateCollectionOptions} for that. + * + * @field embeddingApiKey - The embedding service's API-key/headers (for $vectorize) + * @field defaultMaxTimeMS - Default `maxTimeMS` for all collection operations + * @field logging - Logging configuration overrides + * @field serdes - Additional serialization/deserialization configuration * * @public */ -export interface CollectionOptions { +export interface CollectionOptions extends WithKeyspace { /** - * Options related to vector search. + * The API key for the embedding service to use, or the {@link EmbeddingHeadersProvider} if using + * a provider that requires it (e.g. AWS bedrock). */ - vector?: CollectionVectorOptions, + embeddingApiKey?: string | EmbeddingHeadersProvider | null, /** - * Options related to indexing. + * The configuration for logging events emitted by the {@link DataAPIClient}. + * + * This can be set at any level of the major class hierarchy, and will be inherited by all child classes. + * + * See {@link DataAPILoggingConfig} for *much* more information on configuration, outputs, and inheritance. */ - indexing?: CollectionIndexingOptions, + logging?: DataAPILoggingConfig, + serdes?: CollectionSerDesConfig, /** - * Options related to the default ID. + * ##### Overview + * + * The default timeout options for any operation performed on this {@link Collection} instance. + * + * See {@link TimeoutDescriptor} for much more information about timeouts. + * + * @example + * ```ts + * // The request timeout for all operations is set to 1000ms. + * const client = new DataAPIClient('...', { + *   timeoutDefaults: { requestTimeoutMs: 1000 }, + * }); + * + * // The request timeout for all operations borne from this Db is set to 2000ms. + * const db = client.db('...', { + *   timeoutDefaults: { requestTimeoutMs: 2000 }, + * }); + * ``` + * + * ##### Inheritance + * + * The timeout options are inherited by all child classes, and can be overridden at any level, including the individual method level. + * + * Individual-method-level overrides can vary in behavior depending on the method; again, see {@link TimeoutDescriptor}. + * + * ##### Defaults + * + * The default timeout options are as follows: + * - `requestTimeoutMs`: 10000 + * - `generalMethodTimeoutMs`: 30000 + * - `collectionAdminTimeoutMs`: 60000 + * - `tableAdminTimeoutMs`: 30000 + * - `databaseAdminTimeoutMs`: 600000 + * - `keyspaceAdminTimeoutMs`: 30000 + * + * @see TimeoutDescriptor */ - defaultId?: CollectionDefaultIdOptions, + timeoutDefaults?: Partial, } diff --git a/src/db/types/collections/collections-common.ts b/src/db/types/collections/collections-common.ts index 326bb21f..a10a4989 100644 --- a/src/db/types/collections/collections-common.ts +++ b/src/db/types/collections/collections-common.ts @@ -13,7 +13,7 @@ // limitations under the License. import { SomeDoc } from '@/src/documents/collections'; -import { ToDotNotation } from '@/src/documents/collections/types/dot-notation'; +import { ToDotNotation } from '@/src/documents/types/dot-notation'; import { nullish } from '@/src/lib'; /** @@ -53,6 +53,14 @@ export interface CollectionVectorOptions { * or through {@link DbAdmin.findEmbeddingProviders}. */ service?: VectorizeServiceOptions, + /** + * Configures the index with the fastest settings for a given source of embeddings vectors. + * + * As of time of writing, example `sourceModel`s include `'openai-v3-large'`, `'cohere-v3'`, `'bert'`, and a handful of others. + * + * If no source model if provided, this setting will default to `'other'`. + */ + sourceModel?: string, } /** diff --git a/src/db/types/collections/create-collection.ts b/src/db/types/collections/create-collection.ts index ac82fa87..4299fca8 100644 --- a/src/db/types/collections/create-collection.ts +++ b/src/db/types/collections/create-collection.ts @@ -14,7 +14,7 @@ import { SomeDoc } from '@/src/documents/collections'; import { TimeoutDescriptor } from '@/src/lib'; -import { CollectionOptions, CollectionSpawnOptions } from '@/src/db'; +import { CollectionDefinition, CollectionOptions } from '@/src/db'; /** * Options for creating a new collection (via {@link Db.createCollection}). @@ -31,6 +31,6 @@ import { CollectionOptions, CollectionSpawnOptions } from '@/src/db'; * * @public */ -export interface CreateCollectionOptions extends CollectionOptions, CollectionSpawnOptions { +export interface CreateCollectionOptions extends CollectionDefinition, CollectionOptions { timeout?: number | Pick, 'collectionAdminTimeoutMs'>; } diff --git a/src/db/types/collections/list-collections.ts b/src/db/types/collections/list-collections.ts index 1e4252aa..d474c4b1 100644 --- a/src/db/types/collections/list-collections.ts +++ b/src/db/types/collections/list-collections.ts @@ -13,7 +13,7 @@ // limitations under the License. import type { WithTimeout } from '@/src/lib'; -import { CollectionOptions, WithKeyspace } from '@/src/db'; +import { CollectionDefinition, WithKeyspace } from '@/src/db'; import { SomeDoc } from '@/src/documents'; /** @@ -68,5 +68,5 @@ export interface FullCollectionInfo { /** * The creation options for the collections (i.e. the `vector`, `indexing`, and `defaultId` fields). */ - options: CollectionOptions, + options: CollectionDefinition, } diff --git a/src/db/types/collections/spawn-collection.ts b/src/db/types/collections/spawn-collection.ts deleted file mode 100644 index f50e7e9d..00000000 --- a/src/db/types/collections/spawn-collection.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright DataStax, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import { WithKeyspace } from '@/src/db'; -import { CollectionSerDesConfig, EmbeddingHeadersProvider, SomeDoc } from '@/src/documents'; -import { DataAPILoggingConfig, type TimeoutDescriptor } from '@/src/lib'; - -/** - * Options for spawning a new `Collection` instance through {@link db.collection} or {@link db.createCollection}. - * - * Note that these are not all the options available for when you're actually creating a table—see {@link CreateCollectionOptions} for that. - * - * @field embeddingApiKey - The embedding service's API-key/headers (for $vectorize) - * @field defaultMaxTimeMS - Default `maxTimeMS` for all collection operations - * @field logging - Logging configuration overrides - * @field serdes - Additional serialization/deserialization configuration - * - * @public - */ -export interface CollectionSpawnOptions extends WithKeyspace { - /** - * The API key for the embedding service to use, or the {@link EmbeddingHeadersProvider} if using - * a provider that requires it (e.g. AWS bedrock). - */ - embeddingApiKey?: string | EmbeddingHeadersProvider | null, - /** - * The configuration for logging events emitted by the {@link DataAPIClient}. - * - * This can be set at any level of the major class hierarchy, and will be inherited by all child classes. - * - * See {@link DataAPILoggingConfig} for *much* more information on configuration, outputs, and inheritance. - */ - logging?: DataAPILoggingConfig, - serdes?: CollectionSerDesConfig, - /** - * ##### Overview - * - * The default timeout options for any operation performed on this {@link Collection} instance. - * - * See {@link TimeoutDescriptor} for much more information about timeouts. - * - * @example - * ```ts - * // The request timeout for all operations is set to 1000ms. - * const client = new DataAPIClient('...', { - *   timeoutDefaults: { requestTimeoutMs: 1000 }, - * }); - * - * // The request timeout for all operations borne from this Db is set to 2000ms. - * const db = client.db('...', { - *   timeoutDefaults: { requestTimeoutMs: 2000 }, - * }); - * ``` - * - * ##### Inheritance - * - * The timeout options are inherited by all child classes, and can be overridden at any level, including the individual method level. - * - * Individual-method-level overrides can vary in behavior depending on the method; again, see {@link TimeoutDescriptor}. - * - * ##### Defaults - * - * The default timeout options are as follows: - * - `requestTimeoutMs`: 10000 - * - `generalMethodTimeoutMs`: 30000 - * - `collectionAdminTimeoutMs`: 60000 - * - `tableAdminTimeoutMs`: 30000 - * - `databaseAdminTimeoutMs`: 600000 - * - `keyspaceAdminTimeoutMs`: 30000 - * - * @see TimeoutDescriptor - */ - timeoutDefaults?: Partial, -} diff --git a/src/db/types/index.ts b/src/db/types/index.ts index c5691051..b2f105e4 100644 --- a/src/db/types/index.ts +++ b/src/db/types/index.ts @@ -13,11 +13,11 @@ // limitations under the License. export type * from './collections/collections-common'; -export type * from './collections/collection-options'; +export type * from './collections/collection-definition'; export type * from './collections/create-collection'; export type * from './collections/list-collections'; export type * from './collections/drop-collection'; -export type * from './collections/spawn-collection'; +export type * from './collections/collection-options'; export type * from './tables/alter-table'; export type * from './tables/create-table'; diff --git a/src/db/types/tables/create-table.ts b/src/db/types/tables/create-table.ts index f2b37cfd..389e0bc4 100644 --- a/src/db/types/tables/create-table.ts +++ b/src/db/types/tables/create-table.ts @@ -14,7 +14,7 @@ import { VectorizeServiceOptions } from '@/src/db'; import { WithTimeout } from '@/src/lib'; -import { TableSpawnOptions } from '@/src/db/types/tables/spawn-table'; +import { TableOptions } from '@/src/db/types/tables/spawn-table'; import { SomeRow } from '@/src/documents'; /** @@ -33,7 +33,7 @@ import { SomeRow } from '@/src/documents'; * * @public */ -export interface CreateTableOptions extends WithTimeout<'tableAdminTimeoutMs'>, TableSpawnOptions { +export interface CreateTableOptions extends WithTimeout<'tableAdminTimeoutMs'>, TableOptions { definition: Def, ifNotExists?: boolean, } diff --git a/src/db/types/tables/spawn-table.ts b/src/db/types/tables/spawn-table.ts index 525ceb60..80a49bff 100644 --- a/src/db/types/tables/spawn-table.ts +++ b/src/db/types/tables/spawn-table.ts @@ -28,7 +28,7 @@ import { DataAPILoggingConfig, type TimeoutDescriptor } from '@/src/lib'; * * @public */ -export interface TableSpawnOptions extends WithKeyspace { +export interface TableOptions extends WithKeyspace { /** * The API key for the embedding service to use, or the {@link EmbeddingHeadersProvider} if using * a provider that requires it (e.g. AWS bedrock). diff --git a/src/db/types/tables/table-schema.ts b/src/db/types/tables/table-schema.ts index 776c7da4..4ab2af7a 100644 --- a/src/db/types/tables/table-schema.ts +++ b/src/db/types/tables/table-schema.ts @@ -21,7 +21,7 @@ import { FullCreateTablePrimaryKeyDefinition, } from '@/src/db/types/tables/create-table'; import { EmptyObj } from '@/src/lib/types'; -import { UUID, InetAddress, CqlDate, CqlDuration, CqlTime, CqlTimestamp, CqlBlob } from '@/src/documents'; +import { UUID, InetAddress, DataAPIDate, DataAPIDuration, DataAPITime, DataAPITimestamp, DataAPIBlob } from '@/src/documents'; import { TypeErr } from '@/src/documents/utils'; import { DataAPIVector } from '@/src/documents/datatypes/vector'; import BigNumber from 'bignumber.js'; @@ -91,12 +91,12 @@ export type InferrableTable = * // for type inference purposes for `insert*` operations * type _Proof = Equal, * [$PrimaryKeyType]?: { * name: string, * height: TypeErr<'Field `height` not found as property in table definition'>, - * dob: CqlTimestamp, + * dob: DataAPITimestamp, * } * }>; * @@ -168,12 +168,12 @@ export type Normalize = { [K in keyof T]: T[K] } & EmptyObj; * // for type inference purposes for `insert*` operations * type _Proof = Equal, * [$PrimaryKeyType]?: { * name: string, * height: TypeErr<'Field `height` not found as property in table definition'>, - * dob: CqlTimestamp, + * dob: DataAPITimestamp, * } * }>; * @@ -235,7 +235,7 @@ type PickCqlType = * // number * CqlType2TSType<'int', ...> * - * // CqlDuration + * // DataAPIDuration * CqlType2TSType<'duration', ...> * * // Map @@ -263,19 +263,19 @@ export type CqlType2TSType = interface CqlNonGenericType2TSTypeDict { ascii: string | null, bigint: number | null, - blob: CqlBlob | null, + blob: DataAPIBlob | null, boolean: boolean | null, - date: CqlDate | null, + date: DataAPIDate | null, decimal: BigNumber | null, double: number | null, - duration: CqlDuration | null, + duration: DataAPIDuration | null, float: number | null, int: number | null, inet: InetAddress | null, smallint: number | null, text: string | null; - time: CqlTime | null, - timestamp: CqlTimestamp | null, + time: DataAPITime | null, + timestamp: DataAPITimestamp | null, tinyint: number | null, uuid: UUID | null, varchar: string | null, diff --git a/src/documents/collections/collection.ts b/src/documents/collections/collection.ts index e7f03abc..895b899c 100644 --- a/src/documents/collections/collection.ts +++ b/src/documents/collections/collection.ts @@ -30,7 +30,7 @@ import type { CollectionUpdateManyResult, CollectionUpdateOneOptions, CollectionUpdateOneResult, - Filter, + CollectionFilter, Flatten, FoundDoc, IdOf, @@ -38,10 +38,10 @@ import type { NoId, SomeDoc, ToDotNotation, - UpdateFilter, + CollectionUpdateFilter, WithId, } from '@/src/documents/collections/types'; -import { CollectionOptions, CollectionSpawnOptions, Db } from '@/src/db'; +import { CollectionDefinition, CollectionOptions, Db } from '@/src/db'; import { BigNumberHack, DataAPIHttpClient } from '@/src/lib/api/clients/data-api-http-client'; import { DeepPartial, WithTimeout } from '@/src/lib'; import { CommandImpls } from '@/src/documents/commands/command-impls'; @@ -124,7 +124,7 @@ const jbi = JBI({ storeAsString: true }); * * ###### Custom datatypes * - * You can plug in your own custom datatypes by providing some custom serialization/deserialization logic through the `serdes` option in {@link CollectionSpawnOptions}, {@link DbSpawnOptions} & {@link DataAPIClientOptions.dbOptions}. + * You can plug in your own custom datatypes by providing some custom serialization/deserialization logic through the `serdes` option in {@link CollectionOptions}, {@link DbOptions} & {@link DataAPIClientOptions.dbOptions}. * * See {@link CollectionSerDesConfig} for much more information, but here's a quick example: * @@ -173,7 +173,7 @@ const jbi = JBI({ storeAsString: true }); * @see Db.collection * @see CollectionDefaultIdOptions * @see CollectionSerDesConfig - * @see CollectionSpawnOptions + * @see CollectionOptions * * @public */ @@ -197,7 +197,7 @@ export class Collection { * * @internal */ - constructor(db: Db, httpClient: DataAPIHttpClient, name: string, opts: CollectionSpawnOptions | undefined) { + constructor(db: Db, httpClient: DataAPIHttpClient, name: string, opts: CollectionOptions | undefined) { Object.defineProperty(this, 'name', { value: name, writable: false, @@ -244,7 +244,7 @@ export class Collection { * * ##### The `_id` field * - * If the document does not contain an `_id` field, the server will generate an id for the document. The type of the id may be specified in {@link CollectionOptions.defaultId} at collection creation, otherwise it'll just be a raw UUID string. This generation does not mutate the document. + * If the document does not contain an `_id` field, the server will generate an id for the document. The type of the id may be specified in {@link CollectionDefinition.defaultId} at collection creation, otherwise it'll just be a raw UUID string. This generation does not mutate the document. * * If an `_id` is provided which corresponds to a document that already exists in the collection, a {@link DataAPIResponseError} is raised, and the insertion fails. * @@ -327,7 +327,7 @@ export class Collection { * * ##### The `_id` field * - * If any document does not contain an `_id` field, the server will generate an id for the document. The type of the id may be specified in {@link CollectionOptions.defaultId} at creation, otherwise it'll just be a UUID string. This generation will not mutate the documents. + * If any document does not contain an `_id` field, the server will generate an id for the document. The type of the id may be specified in {@link CollectionDefinition.defaultId} at creation, otherwise it'll just be a UUID string. This generation will not mutate the documents. * * If any `_id` is provided which corresponds to a document that already exists in the collection, an {@link CollectionInsertManyError} is raised, and the insertion (partially) fails. * @@ -410,7 +410,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the document. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the document. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -418,7 +418,7 @@ export class Collection { * * ##### Update operators * - * The update filter can contain a variety of operators to modify the document. See {@link UpdateFilter} for more information & examples. + * The update filter can contain a variety of operators to modify the document. See {@link CollectionUpdateFilter} for more information & examples. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available update operators. * @@ -448,7 +448,7 @@ export class Collection { * @see StrictUpdateFilter * @see StrictSort */ - public async updateOne(filter: Filter, update: UpdateFilter, options?: CollectionUpdateOneOptions): Promise> { + public async updateOne(filter: CollectionFilter, update: CollectionUpdateFilter, options?: CollectionUpdateOneOptions): Promise> { return this.#commands.updateOne(filter, update, options); } @@ -484,7 +484,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the document. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the document. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -492,7 +492,7 @@ export class Collection { * * ##### Update operators * - * The update filter can contain a variety of operators to modify the document. See {@link UpdateFilter} for more information & examples. + * The update filter can contain a variety of operators to modify the document. See {@link CollectionUpdateFilter} for more information & examples. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available update operators. * @@ -523,7 +523,7 @@ export class Collection { * @see StrictFilter * @see StrictUpdateFilter */ - public async updateMany(filter: Filter, update: UpdateFilter, options?: CollectionUpdateManyOptions): Promise> { + public async updateMany(filter: CollectionFilter, update: CollectionUpdateFilter, options?: CollectionUpdateManyOptions): Promise> { return this.#commands.updateMany(filter, update, options); } @@ -557,7 +557,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the document. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the document. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -587,7 +587,7 @@ export class Collection { * @see StrictFilter * @see StrictSort */ - public async replaceOne(filter: Filter, replacement: NoId, options?: CollectionReplaceOneOptions): Promise> { + public async replaceOne(filter: CollectionFilter, replacement: NoId, options?: CollectionReplaceOneOptions): Promise> { return this.#commands.replaceOne(filter, replacement, options); } @@ -604,7 +604,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the document. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the document. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -628,7 +628,7 @@ export class Collection { * @see StrictFilter * @see StrictSort */ - public async deleteOne(filter: Filter, options?: CollectionDeleteOneOptions): Promise { + public async deleteOne(filter: CollectionFilter, options?: CollectionDeleteOneOptions): Promise { return this.#commands.deleteOne(filter, options); } @@ -656,7 +656,7 @@ export class Collection { * * **If an empty filter is passed, all documents in the collection will atomically be deleted in a single API call. Proceed with caution.** * - * The filter can contain a variety of operators & combinators to select the documents. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the documents. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -678,7 +678,7 @@ export class Collection { * * @see StrictFilter */ - public async deleteMany(filter: Filter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise { + public async deleteMany(filter: CollectionFilter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise { return this.#commands.deleteMany(filter, options); } @@ -701,7 +701,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the documents. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the documents. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -791,7 +791,7 @@ export class Collection { * @see StrictSort * @see StrictProjection */ - public find(filter: Filter, options?: CollectionFindOptions & { projection?: never }): CollectionFindCursor, FoundDoc> + public find(filter: CollectionFilter, options?: CollectionFindOptions & { projection?: never }): CollectionFindCursor, FoundDoc> /** * ##### Overview @@ -849,7 +849,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the documents. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the documents. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -939,9 +939,9 @@ export class Collection { * @see StrictSort * @see StrictProjection */ - public find>(filter: Filter, options: CollectionFindOptions): CollectionFindCursor, FoundDoc> + public find>(filter: CollectionFilter, options: CollectionFindOptions): CollectionFindCursor, FoundDoc> - public find(filter: Filter, options?: CollectionFindOptions): CollectionFindCursor { + public find(filter: CollectionFilter, options?: CollectionFindOptions): CollectionFindCursor { return this.#commands.find(filter, options, CollectionFindCursor); } @@ -963,7 +963,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the document. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the document. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -1035,7 +1035,7 @@ export class Collection { * @see StrictSort * @see StrictProjection */ - public async findOne(filter: Filter, options?: CollectionFindOneOptions & { projection?: never }): Promise | null> + public async findOne(filter: CollectionFilter, options?: CollectionFindOneOptions & { projection?: never }): Promise | null> /** * ##### Overview @@ -1090,7 +1090,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the document. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the document. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -1162,9 +1162,9 @@ export class Collection { * @see StrictSort * @see StrictProjection */ - public async findOne>(filter: Filter, options: CollectionFindOneOptions): Promise | null> + public async findOne>(filter: CollectionFilter, options: CollectionFindOneOptions): Promise | null> - public async findOne(filter: Filter, options?: CollectionFindOneOptions): Promise { + public async findOne(filter: CollectionFilter, options?: CollectionFindOneOptions): Promise { return this.#commands.findOne(filter, options); } @@ -1232,13 +1232,14 @@ export class Collection { * * @param key - The dot-notation key to pick which values to retrieve unique * @param filter - A filter to select the documents to find. If not provided, all documents will be matched. + * @param options - The options for this operation. * * @returns A list of all the unique values selected by the given `key` * * @see StrictFilter */ - public async distinct(key: Key, filter: Filter): Promise>)[Key]>[]> { - return this.#commands.distinct(key, filter, CollectionFindCursor); + public async distinct(key: Key, filter: CollectionFilter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise>)[Key]>[]> { + return this.#commands.distinct(key, filter, options, CollectionFindCursor); } /** @@ -1288,7 +1289,7 @@ export class Collection { * * @see StrictFilter */ - public async countDocuments(filter: Filter, upperBound: number, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise { + public async countDocuments(filter: CollectionFilter, upperBound: number, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise { return this.#commands.countDocuments(filter, upperBound, options, TooManyDocumentsToCountError); } @@ -1400,7 +1401,7 @@ export class Collection { * * @see StrictFilter */ - public async findOneAndReplace>(filter: Filter, replacement: NoId, options?: CollectionFindOneAndReplaceOptions): Promise { + public async findOneAndReplace>(filter: CollectionFilter, replacement: NoId, options?: CollectionFindOneAndReplaceOptions): Promise { return this.#commands.findOneAndReplace(filter, replacement, options); } @@ -1438,7 +1439,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the document. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the document. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -1451,7 +1452,7 @@ export class Collection { * * @see StrictFilter */ - public async findOneAndDelete>(filter: Filter, options?: CollectionFindOneAndDeleteOptions): Promise { + public async findOneAndDelete>(filter: CollectionFilter, options?: CollectionFindOneAndDeleteOptions): Promise { return this.#commands.findOneAndDelete(filter, options); } @@ -1525,7 +1526,7 @@ export class Collection { * * ##### Filtering * - * The filter can contain a variety of operators & combinators to select the document. See {@link Filter} & {@link StrictFilter} for much more information. + * The filter can contain a variety of operators & combinators to select the document. See {@link CollectionFilter} & {@link StrictFilter} for much more information. * * The [DataStax documentation site](https://docs.datastax.com/en/astra-db-serverless/index.html) also contains further information on the available filter operators. * @@ -1540,7 +1541,7 @@ export class Collection { * @see StrictFilter * @see StrictUpdateFilter */ - public async findOneAndUpdate(filter: Filter, update: UpdateFilter, options?: CollectionFindOneAndUpdateOptions): Promise | null> { + public async findOneAndUpdate(filter: CollectionFilter, update: CollectionUpdateFilter, options?: CollectionFindOneAndUpdateOptions): Promise | null> { return this.#commands.findOneAndUpdate(filter, update, options); } @@ -1562,7 +1563,7 @@ export class Collection { * * @returns The options that the collection was created with (i.e. the `vector` and `indexing` operations). */ - public async options(options?: WithTimeout<'collectionAdminTimeoutMs'>): Promise> { + public async options(options?: WithTimeout<'collectionAdminTimeoutMs'>): Promise> { const results = await this.#db.listCollections({ timeout: options?.timeout, keyspace: this.keyspace }); const collection = results.find((c) => c.name === this.name); diff --git a/src/documents/collections/cursor.ts b/src/documents/collections/cursor.ts index d7080cef..5ad19c46 100644 --- a/src/documents/collections/cursor.ts +++ b/src/documents/collections/cursor.ts @@ -12,10 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Collection, FindCursor, type SomeDoc } from '@/src/documents'; +import { Collection, CollectionFilter, FindCursor, type SomeDoc } from '@/src/documents'; export class CollectionFindCursor extends FindCursor { public override get dataSource(): Collection { return super.dataSource as Collection; } + + public override filter(filter: CollectionFilter): FindCursor { + return super.filter(filter); + } } diff --git a/src/documents/collections/types/filter.ts b/src/documents/collections/types/filter.ts index 22e218f5..9b9b05fc 100644 --- a/src/documents/collections/types/filter.ts +++ b/src/documents/collections/types/filter.ts @@ -16,49 +16,14 @@ import type { SomeDoc } from '@/src/documents/collections'; import type { IdOf, NoId, ToDotNotation } from '@/src/documents'; import { EmptyObj } from '@/src/lib/types'; import { IsDate, IsNum } from '@/src/documents/types/utils'; - -// @example -// ```ts -// // Get all documents -// const cursor = await collection.find({}, { limit: 10 }); -// -// // Get documents by field equality -// const cursor = await collection.find({ name: 'John Doe' }); -// -// // Get documents by field inequality -// const cursor = await collection.find({ name: { $ne: 'John Doe' } }); -// -// // Get documents by field existence -// const cursor = await collection.find({ name: { $exists: true } }); -// -// // Get documents by matching a field in a list -// const cursor = await collection.find({ name: { $in: ['John Doe', 'Jane Doe'] } }); -// -// // Get documents by field numerical comparison -// const cursor = await collection.find({ age: { $gte: 21 } }); -// const cursor = await collection.find({ age: { $lt: new Date() } }); -// -// // Get documents by combining filters -// const cursor = await collection.find({ name: 'John Doe', age: { $gte: 21 } }); -// -// // Get documents by complex filters combinators -// const cursor = await collection.find({ -//   $not: { -//   $or: [ -//   { name: 'John Doe' }, -//   { age: { $gte: 21 } }, -//   ], -//   friends: { $size: 5 }, -//   }, -// }); -// ``` +import BigNumber from 'bignumber.js'; /** * Represents some filter operation for a given document schema. * - * **If you want stricter type-checking and full auto-complete, see {@link StrictFilter}.** + * **If you want stricter type-checking and full auto-complete, see {@link StrictCollectionFilter}.** * - * This is a more relaxed version of {@link StrictFilter} that doesn't type-check nested fields. + * This is a more relaxed version of {@link StrictCollectionFilter} that doesn't type-check nested fields. * * @example * ```typescript @@ -71,21 +36,21 @@ import { IsDate, IsNum } from '@/src/documents/types/utils'; *   $and: [ *   { _id: { $in: ['abc', 'def'] } }, *   { $not: { arr: { $size: 0 } } }, - *   ] + *   ], * }); * ``` * - * @see StrictFilter + * @see StrictCollectionFilter * * @public */ -export type Filter = { - [K in keyof NoId]?: FilterExpr[K]> +export type CollectionFilter = { + [K in keyof ToDotNotation>]?: CollectionFilterExpr>[K]> } & { - _id?: FilterExpr>, - $and?: Filter[], - $or?: Filter[], - $not?: Filter, + _id?: CollectionFilterExpr>, + $and?: CollectionFilter[], + $or?: CollectionFilter[], + $not?: CollectionFilter, } & { [key: string]: any, } @@ -93,9 +58,9 @@ export type Filter = { /** * Represents some filter operation for a given document schema. * - * **If you want relaxed type-checking, see {@link Filter}.** + * **If you want relaxed type-checking, see {@link CollectionFilter}.** * - * This is a stricter version of {@link Filter} that type-checks nested fields. + * This is a stricter version of {@link CollectionFilter} that type-checks nested fields. * * You can use it anywhere by using the `satisfies` keyword, or by creating a temporary const with the StrictFilter type. * @@ -114,17 +79,17 @@ export type Filter = { * } satisfies StrictFilter); * ``` * - * @see Filter + * @see CollectionFilter * * @public */ -export type StrictFilter = { - [K in keyof ToDotNotation>]?: FilterExpr>[K]> +export type StrictCollectionFilter = { + [K in keyof ToDotNotation>]?: StrictCollectionFilterExpr>[K]> } & { - _id?: FilterExpr>, - $and?: StrictFilter[], - $or?: StrictFilter[], - $not?: StrictFilter, + _id?: StrictCollectionFilterExpr>, + $and?: StrictCollectionFilter[], + $or?: StrictCollectionFilter[], + $not?: StrictCollectionFilter, } /** @@ -132,25 +97,32 @@ export type StrictFilter = { * * @public */ -export type FilterExpr = Elem | FilterOps; +export type CollectionFilterExpr = Elem | (CollectionFilterOps & { [key: string]: any }); + +/** + * Represents an expression in a filter statement, such as an exact value, or a filter operator + * + * @public + */ +export type StrictCollectionFilterExpr = Elem | CollectionFilterOps; /** * Represents filter operators such as `$eq` and `$in` (but not statements like `$and`) * * @public */ -export type FilterOps = { +export type CollectionFilterOps = { $eq?: Elem, $ne?: Elem, $in?: Elem[], $nin?: Elem[] /* I can't un-see this as 'Nine-Inch Nails'... */, $exists?: boolean, } & ( - IsNum extends false ? EmptyObj : NumFilterOps + IsNum extends false ? EmptyObj : CollectionNumFilterOps ) & ( - IsDate extends false ? EmptyObj : (DateFilterOps | Date) + IsDate extends false ? EmptyObj : (CollectionDateFilterOps | Date) ) & ( - any[] extends Elem ? ArrayFilterOps : EmptyObj + any[] extends Elem ? CollectionArrayFilterOps : EmptyObj ) /** @@ -158,23 +130,23 @@ export type FilterOps = { * * @public */ -export interface NumFilterOps { +export interface CollectionNumFilterOps { /** * Less than (exclusive) some number */ - $lt?: number | bigint, + $lt?: number | bigint | BigNumber, /** * Less than or equal to some number */ - $lte?: number | bigint, + $lte?: number | bigint | BigNumber, /** * Greater than (exclusive) some number */ - $gt?: number | bigint, + $gt?: number | bigint | BigNumber, /** * Greater than or equal to some number */ - $gte?: number | bigint, + $gte?: number | bigint | BigNumber, } /** @@ -182,7 +154,7 @@ export interface NumFilterOps { * * @public */ -export interface DateFilterOps { +export interface CollectionDateFilterOps { /** * Less than (exclusive) some date. * @@ -214,7 +186,7 @@ export interface DateFilterOps { * * @public */ -export interface ArrayFilterOps { +export interface CollectionArrayFilterOps { /** * Checks if the array is of a certain size. */ diff --git a/src/documents/collections/types/find/find-one-delete.ts b/src/documents/collections/types/find/find-one-delete.ts index 72cf450c..c28d048b 100644 --- a/src/documents/collections/types/find/find-one-delete.ts +++ b/src/documents/collections/types/find/find-one-delete.ts @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import type { Projection, Sort } from '@/src/documents'; -import type { WithTimeout } from '@/src/lib'; +import type { GenericFindOneAndDeleteOptions } from '@/src/documents'; /** * Represents the options for the `findOneAndDelete` command. @@ -26,51 +25,4 @@ import type { WithTimeout } from '@/src/lib'; * * @public */ -export interface CollectionFindOneAndDeleteOptions extends WithTimeout<'generalMethodTimeoutMs'> { - /** - * The order in which to apply the update if the filter selects multiple documents. - * - * If multiple documents match the filter, only one will be updated. - * - * Defaults to `null`, where the order is not guaranteed. - * @defaultValue null - */ - sort?: Sort, - /** - * Specifies which fields should be included/excluded in the returned documents. - * - * If not specified, all fields are included. - * - * When specifying a projection, it's the user's responsibility to handle the return type carefully, as the - * projection will, of course, affect the shape of the returned documents. It may be a good idea to cast - * the returned documents into a type that reflects the projection to avoid runtime errors. - * - * @example - * ```typescript - * interface User { - *   name: string; - *   age: number; - * } - * - * const collection = db.collection('users'); - * - * const doc = await collection.findOne({}, { - *   projection: { - *   _id: 0, - *   name: 1, - *   }, - *   vector: [.12, .52, .32], - *   includeSimilarity: true, - * }) as { name: string, $similarity: number }; - * - * // Ok - * console.log(doc.name); - * console.log(doc.$similarity); - * - * // Causes type error - * console.log(doc._id); - * console.log(doc.age); - * ``` - */ - projection?: Projection, -} +export type CollectionFindOneAndDeleteOptions = GenericFindOneAndDeleteOptions; diff --git a/src/documents/collections/types/find/find-one-replace.ts b/src/documents/collections/types/find/find-one-replace.ts index abf7b888..b7ec0645 100644 --- a/src/documents/collections/types/find/find-one-replace.ts +++ b/src/documents/collections/types/find/find-one-replace.ts @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import type { Projection, Sort } from '@/src/documents'; -import type { WithTimeout } from '@/src/lib'; +import { GenericFindOneAndReplaceOptions } from '@/src/documents'; /** * Represents the options for the `findOneAndReplace` command. @@ -28,74 +27,4 @@ import type { WithTimeout } from '@/src/lib'; * * @public */ -export interface CollectionFindOneAndReplaceOptions extends WithTimeout<'generalMethodTimeoutMs'> { - /** - * Specifies whether to return the document before or after the update. - * - * Set to `before` to return the document before the update to see the original state of the document. - * - * Set to `after` to return the document after the update to see the updated state of the document immediately. - * - * Defaults to `'before'`. - * - * @defaultValue 'before' - */ - returnDocument?: 'before' | 'after', - /** - * If true, perform an insert if no documents match the filter. - * - * If false, do not insert if no documents match the filter. - * - * Defaults to false. - * - * @defaultValue false - */ - upsert?: boolean, - /** - * The order in which to apply the update if the filter selects multiple documents. - * - * If multiple documents match the filter, only one will be updated. - * - * Defaults to `null`, where the order is not guaranteed. - * - * @defaultValue null - */ - sort?: Sort, - /** - * Specifies which fields should be included/excluded in the returned documents. - * - * If not specified, all fields are included. - * - * When specifying a projection, it's the user's responsibility to handle the return type carefully, as the - * projection will, of course, affect the shape of the returned documents. It may be a good idea to cast - * the returned documents into a type that reflects the projection to avoid runtime errors. - * - * @example - * ```typescript - * interface User { - *   name: string; - *   age: number; - * } - * - * const collection = db.collection('users'); - * - * const doc = await collection.findOne({}, { - *   projection: { - *   _id: 0, - *   name: 1, - *   }, - *   vector: [.12, .52, .32], - *   includeSimilarity: true, - * }) as { name: string, $similarity: number }; - * - * // Ok - * console.log(doc.name); - * console.log(doc.$similarity); - * - * // Causes type error - * console.log(doc._id); - * console.log(doc.age); - * ``` - */ - projection?: Projection, -} +export type CollectionFindOneAndReplaceOptions = GenericFindOneAndReplaceOptions; diff --git a/src/documents/collections/types/find/find-one-update.ts b/src/documents/collections/types/find/find-one-update.ts index 98ea4457..18b897f8 100644 --- a/src/documents/collections/types/find/find-one-update.ts +++ b/src/documents/collections/types/find/find-one-update.ts @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import type { Projection, Sort } from '@/src/documents'; -import type { WithTimeout } from '@/src/lib'; +import type { GenericFindOneAndUpdateOptions } from '@/src/documents'; /** * Represents the options for the `findOneAndUpdate` command. @@ -29,72 +28,4 @@ import type { WithTimeout } from '@/src/lib'; * * @public */ -export interface CollectionFindOneAndUpdateOptions extends WithTimeout<'generalMethodTimeoutMs'> { - /** - * Specifies whether to return the document before or after the update. - * - * Set to `before` to return the document before the update to see the original state of the document. - * - * Set to `after` to return the document after the update to see the updated state of the document immediately. - * - * Defaults to `'before'`. - * - * @defaultValue 'before' - */ - returnDocument?: 'before' | 'after', - /** - * If true, perform an insert if no documents match the filter. - * - * If false, do not insert if no documents match the filter. - * - * Defaults to false. - * @defaultValue false - */ - upsert?: boolean, - /** - * The order in which to apply the update if the filter selects multiple documents. - * - * If multiple documents match the filter, only one will be updated. - * - * Defaults to `null`, where the order is not guaranteed. - * @defaultValue null - */ - sort?: Sort, - /** - * Specifies which fields should be included/excluded in the returned documents. - * - * If not specified, all fields are included. - * - * When specifying a projection, it's the user's responsibility to handle the return type carefully, as the - * projection will, of course, affect the shape of the returned documents. It may be a good idea to cast - * the returned documents into a type that reflects the projection to avoid runtime errors. - * - * @example - * ```typescript - * interface User { - *   name: string; - *   age: number; - * } - * - * const collection = db.collection('users'); - * - * const doc = await collection.findOne({}, { - *   projection: { - *   _id: 0, - *   name: 1, - *   }, - *   vector: [.12, .52, .32], - *   includeSimilarity: true, - * }) as { name: string, $similarity: number }; - * - * // Ok - * console.log(doc.name); - * console.log(doc.$similarity); - * - * // Causes type error - * console.log(doc._id); - * console.log(doc.age); - * ``` - */ - projection?: Projection, -} +export type CollectionFindOneAndUpdateOptions = GenericFindOneAndUpdateOptions; diff --git a/src/documents/collections/types/index.ts b/src/documents/collections/types/index.ts index 3bfb34e9..4710a32b 100644 --- a/src/documents/collections/types/index.ts +++ b/src/documents/collections/types/index.ts @@ -24,7 +24,7 @@ export type * from './insert/insert-one'; export type * from './update/update-many'; export type * from './update/update-one'; export type * from './update/replace-one'; -export type * from './dot-notation'; +export type * from '../../types/dot-notation'; export type * from './filter'; export type * from './update-filter'; export type * from './document'; diff --git a/src/documents/collections/types/update-filter.ts b/src/documents/collections/types/update-filter.ts index ba156396..cbf08d8d 100644 --- a/src/documents/collections/types/update-filter.ts +++ b/src/documents/collections/types/update-filter.ts @@ -15,55 +15,13 @@ import { SomeDoc, ToDotNotation } from '@/src/documents'; import { TypeErr } from '@/src/documents/utils'; import { IsDate, IsNum } from '@/src/documents/types/utils'; -// The following is some basic usage of the update operators, but please view the above resources for more comprehensive usage (such a pushing multiple docs to an array) -// -// @example -// ```ts -// // Set the value of a field (or create it if it doesn't exist) -// await collection.updateOne({ name: 'John Doe' }, { $set: { name: 'Jane Doe' } }); -// -// // Set the value of a field if an upsert is performed -// await collection.updateOne({ a: 0 }, { $setOnInsert: { b: 1 } }, { upsert: true }); -// -// // Remove a field from the document (if it exists) -// await collection.updateOne({ name: 'John Doe' }, { $unset: { name: '' } }); -// -// // Increment the value of a field -// await collection.updateOne({ name: 'John Doe' }, { $inc: { age: 1 } }); -// -// // Decrement the value of a field -// await collection.updateOne({ name: 'John Doe' }, { $inc: { age: -1 } }); -// -// // Add an element to an array field -// await collection.updateOne({ name: 'John Doe' }, { $push: { friends: 'Emily' } }); -// -// // Remove an element from an array field -// await collection.updateOne({ name: 'John Doe' }, { $pop: { friends: 1 } }); -// -// // Rename a field in the document -// await collection.updateOne({ name: 'John Doe' }, { $rename: { name: 'fullName' } }); -// -// // Set the value of a field to the current date -// await collection.updateOne({ name: 'John Doe' }, { $currentDate: { now: true } }); -// -// // Set the field to the min of the specified value and the existing value -// await collection.updateOne({ name: 'John Doe' }, { $min: { age: 21 } }); -// -// // Set the field to the max of the specified value and the existing value -// await collection.updateOne({ name: 'John Doe' }, { $max: { age: 21 } }); -// -// // Multiply the value of a field by some number -// await collection.updateOne({ name: 'John Doe' }, { $mul: { age: 2 } }); -// -// // Add an element to an array field if it does not already exist -// await collection.updateOne({ name: 'John Doe' }, { $addToSet: { fields: 'Me' } }); -// ``` + /** * Represents the update filter to specify how to update a document. * - * **If you want stricter type-checking and full auto-complete, see {@link StrictUpdateFilter}.** + * **If you want stricter type-checking and full auto-complete, see {@link StrictCollectionUpdateFilter}.** * - * This is a more relaxed version of {@link StrictUpdateFilter} that doesn't type-check nested fields. + * This is a more relaxed version of {@link StrictCollectionUpdateFilter} that doesn't type-check nested fields. * * @example * ```typescript @@ -93,11 +51,11 @@ import { IsDate, IsNum } from '@/src/documents/types/utils'; * @field $mul - Multiply the value of a field in the document. * @field $addToSet - Add an element to an array field in the document if it does not already exist. * - * @see StrictUpdateFilter + * @see StrictCollectionUpdateFilter * * @public */ -export interface UpdateFilter { +export interface CollectionUpdateFilter { /** * Set the value of a field in the document. * @@ -149,7 +107,7 @@ export interface UpdateFilter { * } * ``` */ - $inc?: NumberUpdate & Record, + $inc?: CollectionNumberUpdate & Record, /** * Add an element to an array field in the document. * @@ -162,7 +120,7 @@ export interface UpdateFilter { * } * ``` */ - $push?: Push & SomeDoc, + $push?: CollectionPush & SomeDoc, /** * Remove an element from an array field in the document. * @@ -175,7 +133,7 @@ export interface UpdateFilter { * } * ``` */ - $pop?: Pop & Record, + $pop?: CollectionPop & Record, /** * Rename a field in the document. * @@ -201,7 +159,7 @@ export interface UpdateFilter { * } * ``` */ - $currentDate?: CurrentDate & Record, + $currentDate?: CollectionCurrentDate & Record, /** * Only update the field if the specified value is less than the existing value. * @@ -214,7 +172,7 @@ export interface UpdateFilter { * } * ``` */ - $min?: (NumberUpdate | DateUpdate) & Record, + $min?: (CollectionNumberUpdate | CollectionDateUpdate) & Record, /** * Only update the field if the specified value is greater than the existing value. * @@ -227,7 +185,7 @@ export interface UpdateFilter { * } * ``` */ - $max?: (NumberUpdate | DateUpdate) & Record, + $max?: (CollectionNumberUpdate | CollectionDateUpdate) & Record, /** * Multiply the value of a field in the document. * @@ -240,7 +198,7 @@ export interface UpdateFilter { * } * ``` */ - $mul?: StrictNumberUpdate & Record, + $mul?: StrictCollectionNumberUpdate & Record, /** * Add an element to an array field in the document if it does not already exist. * @@ -253,15 +211,15 @@ export interface UpdateFilter { * } * ``` */ - $addToSet?: Push & SomeDoc, + $addToSet?: CollectionPush & SomeDoc, } /** * Represents the update filter to specify how to update a document. * - * **If you want relaxed type-checking, see {@link UpdateFilter}.** + * **If you want relaxed type-checking, see {@link CollectionUpdateFilter}.** * - * This is a stricter version of {@link UpdateFilter} that type-checks nested fields. + * This is a stricter version of {@link CollectionUpdateFilter} that type-checks nested fields. * * You can use it anywhere by using the `satisfies` keyword, or by creating a temporary const with the StrictUpdateFilter type. * @@ -293,11 +251,11 @@ export interface UpdateFilter { * @field $mul - Multiply the value of a field in the document. * @field $addToSet - Add an element to an array field in the document if it does not already exist. * - * @see UpdateFilter + * @see CollectionUpdateFilter * * @public */ -export interface StrictUpdateFilter { +export interface StrictCollectionUpdateFilter { /** * Set the value of a field in the document. * @@ -336,7 +294,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $unset?: StrictUnset, + $unset?: StrictCollectionUnset, /** * Increment the value of a field in the document if it's potentially a `number`. * @@ -349,7 +307,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $inc?: StrictNumberUpdate, + $inc?: StrictCollectionNumberUpdate, /** * Add an element to an array field in the document. * @@ -362,7 +320,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $push?: StrictPush, + $push?: StrictCollectionPush, /** * Remove an element from an array field in the document. * @@ -375,7 +333,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $pop?: StrictPop, + $pop?: StrictCollectionPop, /** * Rename a field in the document. * @@ -388,7 +346,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $rename?: StrictRename, + $rename?: StrictCollectionRename, /** * Set the value of a field to the current date. * @@ -401,7 +359,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $currentDate?: CurrentDate>, + $currentDate?: CollectionCurrentDate>, /** * Only update the field if the specified value is less than the existing value. * @@ -414,7 +372,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $min?: StrictNumberUpdate | StrictDateUpdate, + $min?: StrictCollectionNumberUpdate | StrictCollectionDateUpdate, /** * Only update the field if the specified value is greater than the existing value. * @@ -427,7 +385,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $max?: StrictNumberUpdate | StrictDateUpdate, + $max?: StrictCollectionNumberUpdate | StrictCollectionDateUpdate, /** * Multiply the value of a field in the document. * @@ -440,7 +398,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $mul?: StrictNumberUpdate, + $mul?: StrictCollectionNumberUpdate, /** * Add an element to an array field in the document if it does not already exist. * @@ -453,7 +411,7 @@ export interface StrictUpdateFilter { * } * ``` */ - $addToSet?: StrictPush, + $addToSet?: StrictCollectionPush, } /** @@ -461,7 +419,7 @@ export interface StrictUpdateFilter { * * @public */ -export type StrictUnset = { +export type StrictCollectionUnset = { [K in keyof ToDotNotation]?: '' | true | 1 } @@ -470,8 +428,8 @@ export type StrictUnset = { * * @public */ -export type Pop ={ - [K in keyof ArrayUpdate]?: number +export type CollectionPop = { + [K in keyof CollectionArrayUpdate]?: number } /** @@ -479,8 +437,8 @@ export type Pop ={ * * @public */ -export type StrictPop> = ContainsArr extends true ? { - [K in keyof ArrayUpdate]?: number +export type StrictCollectionPop> = ContainsArr extends true ? { + [K in keyof CollectionArrayUpdate]?: number } : TypeErr<'Can not pop on a schema with no arrays'> /** @@ -488,10 +446,10 @@ export type StrictPop * * @public */ -export type Push = { - [K in keyof ArrayUpdate]?: ( - | ArrayUpdate[K] - | { $each: ArrayUpdate[K][], $position?: number } +export type CollectionPush = { + [K in keyof CollectionArrayUpdate]?: ( + | CollectionArrayUpdate[K] + | { $each: CollectionArrayUpdate[K][], $position?: number } ) } @@ -500,10 +458,10 @@ export type Push = { * * @public */ -export type StrictPush> = ContainsArr extends true ? { - [K in keyof ArrayUpdate]?: ( - | ArrayUpdate[K] - | { $each: ArrayUpdate[K][], $position?: number } +export type StrictCollectionPush> = ContainsArr extends true ? { + [K in keyof CollectionArrayUpdate]?: ( + | CollectionArrayUpdate[K] + | { $each: CollectionArrayUpdate[K][], $position?: number } ) } : TypeErr<'Can not perform array operation on a schema with no arrays'> @@ -512,7 +470,7 @@ export type StrictPush = { +export type StrictCollectionRename = { [K in keyof ToDotNotation]?: string } @@ -521,7 +479,7 @@ export type StrictRename = { * * @public */ -export type NumberUpdate = { +export type CollectionNumberUpdate = { [K in keyof Schema as IsNum extends true ? K : never]?: number | bigint } @@ -530,7 +488,7 @@ export type NumberUpdate = { * * @public */ -export type StrictNumberUpdate> = ContainsNum extends true ? { +export type StrictCollectionNumberUpdate> = ContainsNum extends true ? { [K in keyof InNotation as IsNum extends true ? K : never]?: number | bigint } : TypeErr<'Can not perform a number operation on a schema with no numbers'>; @@ -539,7 +497,7 @@ export type StrictNumberUpdate = { +export type CollectionDateUpdate = { [K in keyof Schema as ContainsDate extends true ? K : never]?: Date | { $date: number } }; @@ -548,7 +506,7 @@ export type DateUpdate = { * * @public */ -export type StrictDateUpdate> = ContainsDate extends true ? { +export type StrictCollectionDateUpdate> = ContainsDate extends true ? { [K in keyof InNotation as ContainsDate extends true ? K : never]?: Date | { $date: number } } : TypeErr<'Can not perform a date operation on a schema with no dates'>; @@ -557,7 +515,7 @@ export type StrictDateUpdate = { +export type CollectionArrayUpdate = { [K in keyof Schema as any[] extends Schema[K] ? K : never]?: PickArrayTypes }; @@ -566,7 +524,7 @@ export type ArrayUpdate = { * * @public */ -export type CurrentDate = { +export type CollectionCurrentDate = { [K in keyof Schema as Schema[K] extends Date | { $date: number } ? K : never]?: boolean }; diff --git a/src/documents/commands/command-impls.ts b/src/documents/commands/command-impls.ts index 9598a4ea..395b8902 100644 --- a/src/documents/commands/command-impls.ts +++ b/src/documents/commands/command-impls.ts @@ -20,7 +20,7 @@ import { CollectionInsertManyOptions, CollectionUpdateManyError, DataAPIDetailedErrorDescriptor, - DataAPIResponseError, + DataAPIResponseError, Filter, FindCursor, GenericDeleteManyResult, GenericDeleteOneOptions, @@ -36,7 +36,8 @@ import { GenericUpdateManyOptions, GenericUpdateOneOptions, GenericUpdateResult, - SomeDoc, Table, + SomeDoc, + Table, UpdateFilter, } from '@/src/documents'; import { nullish, WithTimeout } from '@/src/lib'; import { insertManyOrdered, insertManyUnordered } from '@/src/documents/commands/helpers/insertion'; @@ -88,7 +89,7 @@ export class CommandImpls { }; } - public async updateOne(_filter: SomeDoc, _update: SomeDoc, options?: GenericUpdateOneOptions): Promise> { + public async updateOne(_filter: Filter, _update: UpdateFilter, options?: GenericUpdateOneOptions): Promise> { const filter = this.#serdes.serializeRecord(_filter); const update = this.#serdes.serializeRecord(_update); @@ -108,7 +109,7 @@ export class CommandImpls { return coalesceUpsertIntoUpdateResult(mkUpdateResult(resp), resp); } - public async updateMany(_filter: SomeDoc, _update: SomeDoc, options?: GenericUpdateManyOptions): Promise> { + public async updateMany(_filter: Filter, _update: UpdateFilter, options?: GenericUpdateManyOptions): Promise> { const filter = this.#serdes.serializeRecord(_filter); const update = this.#serdes.serializeRecord(_update); @@ -153,7 +154,7 @@ export class CommandImpls { return coalesceUpsertIntoUpdateResult(commonResult, resp); } - public async replaceOne(_filter: SomeDoc, _replacement: SomeDoc, options?: GenericReplaceOneOptions): Promise> { + public async replaceOne(_filter: Filter, _replacement: SomeDoc, options?: GenericReplaceOneOptions): Promise> { const filter = this.#serdes.serializeRecord(_filter); const replacement = this.#serdes.serializeRecord(_replacement); @@ -175,7 +176,7 @@ export class CommandImpls { return coalesceUpsertIntoUpdateResult(mkUpdateResult(resp), resp); } - public async deleteOne(_filter: SomeDoc, options?: GenericDeleteOneOptions): Promise { + public async deleteOne(_filter: Filter, options?: GenericDeleteOneOptions): Promise { const filter = this.#serdes.serializeRecord(_filter); const command = mkCmdWithSortProj('deleteOne', options, { @@ -192,7 +193,7 @@ export class CommandImpls { }; } - public async deleteMany(_filter: SomeDoc, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise { + public async deleteMany(_filter: Filter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise { const filter = this.#serdes.serializeRecord(_filter); const command = mkBasicCmd('deleteMany', { @@ -226,14 +227,14 @@ export class CommandImpls { }; } - public find>(filter: SomeDoc, options: GenericFindOptions | undefined, cursor: new (...args: ConstructorParameters>) => Cursor): Cursor { + public find>(filter: Filter, options: GenericFindOptions | undefined, cursor: new (...args: ConstructorParameters>) => Cursor): Cursor { if (options?.sort) { options.sort = normalizedSort(options.sort); } return new cursor(this.#tOrC as any, this.#serdes, this.#serdes.serializeRecord(structuredClone(filter)), structuredClone(options)); } - public async findOne(_filter: SomeDoc, options?: GenericFindOneOptions): Promise { + public async findOne(_filter: Filter, options?: GenericFindOneOptions): Promise { const filter = this.#serdes.serializeRecord(_filter); const command = mkCmdWithSortProj('findOne', options, { @@ -251,7 +252,7 @@ export class CommandImpls { return this.#serdes.deserializeRecord(resp.data?.document, resp) as any; } - public async findOneAndReplace(_filter: SomeDoc, _replacement: SomeDoc, options?: GenericFindOneAndReplaceOptions): Promise { + public async findOneAndReplace(_filter: Filter, _replacement: SomeDoc, options?: GenericFindOneAndReplaceOptions): Promise { const filter = this.#serdes.serializeRecord(_filter); const replacement = this.#serdes.serializeRecord(_replacement); @@ -271,7 +272,7 @@ export class CommandImpls { return resp.data?.document || null; } - public async findOneAndDelete(_filter: SomeDoc, options?: GenericFindOneAndDeleteOptions): Promise { + public async findOneAndDelete(_filter: Filter, options?: GenericFindOneAndDeleteOptions): Promise { const filter = this.#serdes.serializeRecord(_filter); const command = mkCmdWithSortProj('findOneAndDelete', options, { @@ -285,7 +286,7 @@ export class CommandImpls { return resp.data?.document || null; } - public async findOneAndUpdate(_filter: SomeDoc, _update: SomeDoc, options?: GenericFindOneAndUpdateOptions): Promise { + public async findOneAndUpdate(_filter: Filter, _update: SomeDoc, options?: GenericFindOneAndUpdateOptions): Promise { const filter = this.#serdes.serializeRecord(_filter); const update = this.#serdes.serializeRecord(_update); @@ -305,9 +306,9 @@ export class CommandImpls { return resp.data?.document || null; } - public async distinct(key: string, filter: SomeDoc, mkCursor: new (...args: ConstructorParameters>) => FindCursor): Promise { + public async distinct(key: string, filter: SomeDoc, options: WithTimeout<'generalMethodTimeoutMs'> | undefined, mkCursor: new (...args: ConstructorParameters>) => FindCursor): Promise { const projection = pullSafeProjection4Distinct(key); - const cursor = this.find(filter, { projection: { _id: 0, [projection]: 1 } }, mkCursor); + const cursor = this.find(filter, { projection: { _id: 0, [projection]: 1 }, timeout: options?.timeout }, mkCursor); const seen = new Set(); const ret = []; @@ -334,7 +335,7 @@ export class CommandImpls { return ret; } - public async countDocuments(_filter: SomeDoc, upperBound: number, options: WithTimeout<'generalMethodTimeoutMs'> | undefined, error: new (count: number, hitLimit: boolean) => Error): Promise { + public async countDocuments(_filter: Filter, upperBound: number, options: WithTimeout<'generalMethodTimeoutMs'> | undefined, error: new (count: number, hitLimit: boolean) => Error): Promise { if (!upperBound) { throw new Error('upperBound is required'); } diff --git a/src/documents/commands/types/find/find-one-delete.ts b/src/documents/commands/types/find/find-one-delete.ts index efa0ed26..52b39786 100644 --- a/src/documents/commands/types/find/find-one-delete.ts +++ b/src/documents/commands/types/find/find-one-delete.ts @@ -15,7 +15,62 @@ import { Projection, Sort } from '@/src/documents'; import { WithTimeout } from '@/src/lib'; +/** + * Represents the options for the `findOneAndDelete` command. + * + * @field sort - The sort order to pick which document to delete if the filter selects multiple documents. + * @field projection - Specifies which fields should be included/excluded in the returned documents. + * @field maxTimeMS - The maximum time to wait for a response from the server, in milliseconds. + * + * @see Collection.findOneAndDelete + * + * @public + */ export interface GenericFindOneAndDeleteOptions extends WithTimeout<'generalMethodTimeoutMs'> { + /** + * The order in which to apply the update if the filter selects multiple documents. + * + * If multiple documents match the filter, only one will be updated. + * + * Defaults to `null`, where the order is not guaranteed. + * @defaultValue null + */ sort?: Sort, + /** + * Specifies which fields should be included/excluded in the returned documents. + * + * If not specified, all fields are included. + * + * When specifying a projection, it's the user's responsibility to handle the return type carefully, as the + * projection will, of course, affect the shape of the returned documents. It may be a good idea to cast + * the returned documents into a type that reflects the projection to avoid runtime errors. + * + * @example + * ```typescript + * interface User { + *   name: string; + *   age: number; + * } + * + * const collection = db.collection('users'); + * + * const doc = await collection.findOne({}, { + *   projection: { + *   _id: 0, + *   name: 1, + *   }, + *   vector: [.12, .52, .32], + *   includeSimilarity: true, + * }) as { name: string, $similarity: number }; + * + * // Ok + * console.log(doc.name); + * console.log(doc.$similarity); + * + * // Causes type error + * console.log(doc._id); + * console.log(doc.age); + * ``` + */ projection?: Projection, } diff --git a/src/documents/commands/types/find/find-one-replace.ts b/src/documents/commands/types/find/find-one-replace.ts index 3e41c3e5..8c4e9e8f 100644 --- a/src/documents/commands/types/find/find-one-replace.ts +++ b/src/documents/commands/types/find/find-one-replace.ts @@ -15,9 +15,87 @@ import { Projection, Sort } from '@/src/documents'; import { WithTimeout } from '@/src/lib'; +/** + * Represents the options for the `findOneAndReplace` command. + * + * @field returnDocument - Specifies whether to return the original or updated document. + * @field upsert - If true, perform an insert if no documents match the filter. + * @field sort - The sort order to pick which document to replace if the filter selects multiple documents. + * @field projection - Specifies which fields should be included/excluded in the returned documents. + * @field maxTimeMS - The maximum time to wait for a response from the server, in milliseconds. + * + * @see Collection.findOneAndReplace + * + * @public + */ export interface GenericFindOneAndReplaceOptions extends WithTimeout<'generalMethodTimeoutMs'> { + /** + * Specifies whether to return the document before or after the update. + * + * Set to `before` to return the document before the update to see the original state of the document. + * + * Set to `after` to return the document after the update to see the updated state of the document immediately. + * + * Defaults to `'before'`. + * + * @defaultValue 'before' + */ returnDocument?: 'before' | 'after', + /** + * If true, perform an insert if no documents match the filter. + * + * If false, do not insert if no documents match the filter. + * + * Defaults to false. + * + * @defaultValue false + */ upsert?: boolean, + /** + * The order in which to apply the update if the filter selects multiple documents. + * + * If multiple documents match the filter, only one will be updated. + * + * Defaults to `null`, where the order is not guaranteed. + * + * @defaultValue null + */ sort?: Sort, + /** + * Specifies which fields should be included/excluded in the returned documents. + * + * If not specified, all fields are included. + * + * When specifying a projection, it's the user's responsibility to handle the return type carefully, as the + * projection will, of course, affect the shape of the returned documents. It may be a good idea to cast + * the returned documents into a type that reflects the projection to avoid runtime errors. + * + * @example + * ```typescript + * interface User { + *   name: string; + *   age: number; + * } + * + * const collection = db.collection('users'); + * + * const doc = await collection.findOne({}, { + *   projection: { + *   _id: 0, + *   name: 1, + *   }, + *   vector: [.12, .52, .32], + *   includeSimilarity: true, + * }) as { name: string, $similarity: number }; + * + * // Ok + * console.log(doc.name); + * console.log(doc.$similarity); + * + * // Causes type error + * console.log(doc._id); + * console.log(doc.age); + * ``` + */ projection?: Projection, } diff --git a/src/documents/commands/types/find/find-one-update.ts b/src/documents/commands/types/find/find-one-update.ts index f964fab2..0542902b 100644 --- a/src/documents/commands/types/find/find-one-update.ts +++ b/src/documents/commands/types/find/find-one-update.ts @@ -15,9 +15,86 @@ import { Projection, Sort } from '@/src/documents'; import { WithTimeout } from '@/src/lib'; +/** + * Represents the options for the `findOneAndUpdate` command. + * + * @field returnDocument - Specifies whether to return the original or updated document. + * @field upsert - If true, perform an insert if no documents match the filter. + * @field sort - The sort order to pick which document to replace if the filter selects multiple documents. + * @field projection - Specifies which fields should be included/excluded in the returned documents. + * @field includeResultMetadata - When true, returns alongside the document, an `ok` field with a value of 1 if the command executed successfully. + * @field maxTimeMS - The maximum time to wait for a response from the server, in milliseconds. + * + * @see Collection.findOneAndUpdate + * + * @public + */ export interface GenericFindOneAndUpdateOptions extends WithTimeout<'generalMethodTimeoutMs'> { + /** + * Specifies whether to return the document before or after the update. + * + * Set to `before` to return the document before the update to see the original state of the document. + * + * Set to `after` to return the document after the update to see the updated state of the document immediately. + * + * Defaults to `'before'`. + * + * @defaultValue 'before' + */ returnDocument?: 'before' | 'after', + /** + * If true, perform an insert if no documents match the filter. + * + * If false, do not insert if no documents match the filter. + * + * Defaults to false. + * @defaultValue false + */ upsert?: boolean, + /** + * The order in which to apply the update if the filter selects multiple documents. + * + * If multiple documents match the filter, only one will be updated. + * + * Defaults to `null`, where the order is not guaranteed. + * @defaultValue null + */ sort?: Sort, + /** + * Specifies which fields should be included/excluded in the returned documents. + * + * If not specified, all fields are included. + * + * When specifying a projection, it's the user's responsibility to handle the return type carefully, as the + * projection will, of course, affect the shape of the returned documents. It may be a good idea to cast + * the returned documents into a type that reflects the projection to avoid runtime errors. + * + * @example + * ```typescript + * interface User { + *   name: string; + *   age: number; + * } + * + * const collection = db.collection('users'); + * + * const doc = await collection.findOne({}, { + *   projection: { + *   _id: 0, + *   name: 1, + *   }, + *   vector: [.12, .52, .32], + *   includeSimilarity: true, + * }) as { name: string, $similarity: number }; + * + * // Ok + * console.log(doc.name); + * console.log(doc.$similarity); + * + * // Causes type error + * console.log(doc._id); + * console.log(doc.age); + * ``` + */ projection?: Projection, } diff --git a/src/documents/cursor.ts b/src/documents/cursor.ts index 41674ab9..bc49c0bf 100644 --- a/src/documents/cursor.ts +++ b/src/documents/cursor.ts @@ -12,15 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -import type { Collection, Filter, SomeDoc } from '@/src/documents/collections'; +import type { Collection, SomeDoc } from '@/src/documents/collections'; import type { GenericFindOptions } from '@/src/documents/commands'; -import type { Projection, Sort } from '@/src/documents/types'; +import type { Filter, Projection, Sort } from '@/src/documents/types'; import type { DeepPartial, nullish } from '@/src/lib'; import { normalizedSort } from '@/src/documents/utils'; import { $CustomInspect } from '@/src/lib/constants'; import type { DataAPISerDes } from '@/src/lib/api/ser-des'; import { DataAPIError } from '@/src/documents/errors'; import type { Table } from '@/src/documents/tables'; +import { TimeoutManager } from '@/src/lib/api/timeouts'; export class CursorError extends DataAPIError { public readonly cursor: FindCursor; @@ -117,7 +118,7 @@ export abstract class FindCursor { readonly #serdes: DataAPISerDes; readonly #options: GenericFindOptions; - readonly #filter: [Filter, boolean]; + readonly #filter: [Filter, boolean]; readonly #mapping?: (doc: any) => T; #buffer: TRaw[] = []; @@ -131,7 +132,7 @@ export abstract class FindCursor { * * @internal */ - constructor(parent: Table | Collection, serdes: DataAPISerDes, filter: [Filter, boolean], options?: GenericFindOptions, mapping?: (doc: TRaw) => T) { + constructor(parent: Table | Collection, serdes: DataAPISerDes, filter: [Filter, boolean], options?: GenericFindOptions, mapping?: (doc: TRaw) => T) { this.#parent = parent; this.#serdes = serdes; this.#filter = filter; @@ -210,7 +211,7 @@ export abstract class FindCursor { * * @see StrictFilter */ - public filter(filter: Filter): FindCursor { + public filter(filter: Filter): FindCursor { if (this.#state !== 'idle') { throw new CursorError('Cannot set a new filter on a running/closed cursor', this); } @@ -492,13 +493,8 @@ export abstract class FindCursor { } try { - while (true) { - const doc = await this.next(); - - if (doc === null) { - break; - } - + let doc: T | null; + while ((doc = await this.#next(false))) { yield doc; } } finally { @@ -551,9 +547,17 @@ export abstract class FindCursor { } const docs: T[] = []; - for await (const doc of this) { - docs.push(doc); + const tm = this.#parent._httpClient.tm.multipart('generalMethodTimeoutMs', this.#options); + + try { + let doc: T | null; + while ((doc = await this.#next(false, tm))) { + docs.push(doc); + } + } finally { + this.close(); } + return docs; } @@ -565,13 +569,13 @@ export abstract class FindCursor { this.#buffer.length = 0; } - #clone(filter: [Filter, boolean], options: GenericFindOptions, mapping?: (doc: RRaw) => R): FindCursor { + #clone(filter: [Filter, boolean], options: GenericFindOptions, mapping?: (doc: RRaw) => R): FindCursor { return new (this.constructor)(this.#parent, this.#serdes, filter, options, mapping); } - async #next(peek: true): Promise - async #next(peek: false): Promise - async #next(peek: boolean): Promise { + async #next(peek: true, tm?: TimeoutManager): Promise + async #next(peek: false, tm?: TimeoutManager): Promise + async #next(peek: boolean, tm?: TimeoutManager): Promise { if (this.#state === 'closed') { return null; } @@ -583,7 +587,7 @@ export abstract class FindCursor { this.close(); return null; } - await this.#getMore(); + await this.#getMore(tm); } if (peek) { @@ -602,7 +606,7 @@ export abstract class FindCursor { } } - async #getMore(): Promise { + async #getMore(tm?: TimeoutManager): Promise { const command: InternalGetMoreCommand = { find: { filter: this.#filter[0], @@ -619,7 +623,7 @@ export abstract class FindCursor { }; const raw = await this.#parent._httpClient.executeCommand(command, { - timeoutManager: this.#parent._httpClient.tm.multipart('generalMethodTimeoutMs', this.#options), + timeoutManager: tm ?? this.#parent._httpClient.tm.single('generalMethodTimeoutMs', this.#options), bigNumsPresent: this.#filter[1], }); diff --git a/src/documents/datatypes/blob.ts b/src/documents/datatypes/blob.ts index af176d64..043c2d68 100644 --- a/src/documents/datatypes/blob.ts +++ b/src/documents/datatypes/blob.ts @@ -15,19 +15,19 @@ import { $SerializeForTable } from '@/src/documents/tables/ser-des'; import { $CustomInspect } from '@/src/lib/constants'; -export type CqlBlobLike = CqlBlob | ArrayBuffer | Buffer | { $binary: string }; +export type DataAPIBlobLike = DataAPIBlob | ArrayBuffer | Buffer | { $binary: string }; -export class CqlBlob { - readonly #raw: Exclude; +export class DataAPIBlob { + readonly #raw: Exclude; public [$SerializeForTable] = () => ({ $binary: this.asBase64() }); - public constructor(blob: CqlBlobLike, validate = true) { - if (validate && !CqlBlob.isBlobLike(blob)) { + public constructor(blob: DataAPIBlobLike, validate = true) { + if (validate && !DataAPIBlob.isBlobLike(blob)) { throw new TypeError(`Expected blob to be a string, ArrayBuffer, or Buffer (got '${blob}')`); } - this.#raw = (blob instanceof CqlBlob) + this.#raw = (blob instanceof DataAPIBlob) ? blob.#raw : blob; @@ -48,7 +48,7 @@ export class CqlBlob { return ~~((this.#raw.$binary.replace(/=+$/, '').length * 3) / 4); } - public raw(): Exclude { + public raw(): Exclude { return this.#raw; } @@ -94,11 +94,11 @@ export class CqlBlob { public toString() { const type = (this.#raw instanceof ArrayBuffer && 'ArrayBuffer') || (this.#raw instanceof Buffer && 'Buffer') || 'base64'; - return `CqlBlob(typeof raw=${type}, byteLength=${this.byteLength})`; + return `DataAPIBlob(typeof raw=${type}, byteLength=${this.byteLength})`; } - public static isBlobLike(value: unknown): value is CqlBlobLike { - return !!value && typeof value === 'object' && (value instanceof CqlBlob || ('$binary' in value && typeof value.$binary === 'string') || value instanceof ArrayBuffer || value instanceof Buffer); + public static isBlobLike(value: unknown): value is DataAPIBlobLike { + return !!value && typeof value === 'object' && (value instanceof DataAPIBlob || ('$binary' in value && typeof value.$binary === 'string') || value instanceof ArrayBuffer || value instanceof Buffer); } } diff --git a/src/documents/datatypes/dates.ts b/src/documents/datatypes/dates.ts index 08bf0ff2..5e5b5fe9 100644 --- a/src/documents/datatypes/dates.ts +++ b/src/documents/datatypes/dates.ts @@ -16,18 +16,18 @@ import { isNullish } from '@/src/lib/utils'; import { $CustomInspect } from '@/src/lib/constants'; import { $SerializeForTable } from '@/src/documents/tables/ser-des'; -export interface CqlDateComponents { +export interface DataAPIDateComponents { year: number, month: number, date: number } -export class CqlDate { +export class DataAPIDate { readonly #date: string; public [$SerializeForTable] = this.toString; - public constructor(input?: string | Date | CqlDateComponents) { + public constructor(input?: string | Date | DataAPIDateComponents) { if (typeof input === 'string') { this.#date = input; } else if (input instanceof Date || isNullish(input)) { @@ -35,17 +35,17 @@ export class CqlDate { this.#date = `${input.getFullYear().toString().padStart(4, '0')}-${(input.getMonth() + 1).toString().padStart(2, '0')}-${input.getDate().toString().padStart(2, '0')}`; } else { if (input.month < 1 || input.month > 12) { - throw new RangeError('Month must be between 1 and 12 (CqlDate month is NOT zero-indexed)'); + throw new RangeError('Month must be between 1 and 12 (DataAPIDate month is NOT zero-indexed)'); } this.#date = `${input.year.toString().padStart(4, '0') ?? '0000'}-${input.month.toString().padStart(2, '0') ?? '00'}-${input.date.toString().padStart(2, '0') ?? '00'}`; } Object.defineProperty(this, $CustomInspect, { - value: () => `CqlDate("${this.#date}")`, + value: () => `DataAPIDate("${this.#date}")`, }); } - public components(): CqlDateComponents { + public components(): DataAPIDateComponents { const signum = this.#date.startsWith('-') ? -1 : 1; const date = this.#date.split('-'); @@ -56,8 +56,8 @@ export class CqlDate { return { year: +date[0], month: +date[1], date: +date[2] }; } - public toDate(base?: Date | CqlTime | CqlTimestamp): Date { - if (base instanceof CqlTimestamp) { + public toDate(base?: Date | DataAPITime | DataAPITimestamp): Date { + if (base instanceof DataAPITimestamp) { base = base.toDate(); } @@ -83,25 +83,25 @@ export class CqlDate { } } -export interface CqlDurationComponents { +export interface DataAPIDurationComponents { months: number, days: number, nanoseconds: number, } -export class CqlDuration { +export class DataAPIDuration { readonly #duration: string; public [$SerializeForTable] = this.toString; - constructor(input: string | Partial | [Date | CqlTimestamp, Date | CqlTimestamp]) { + constructor(input: string | Partial | [Date | DataAPITimestamp, Date | DataAPITimestamp]) { if (typeof input === 'string') { this.#duration = input; } else if (Array.isArray(input)) { - if (input[0] instanceof CqlTimestamp) { + if (input[0] instanceof DataAPITimestamp) { input[0] = input[0].toDate(); } - if (input[1] instanceof CqlTimestamp) { + if (input[1] instanceof DataAPITimestamp) { input[1] = input[1].toDate(); } const [start, end] = input; @@ -112,20 +112,20 @@ export class CqlDuration { } Object.defineProperty(this, $CustomInspect, { - value: () => `CqlDuration("${this.#duration}")`, + value: () => `DataAPIDuration("${this.#duration}")`, }); } - public components(): CqlDurationComponents { + public components(): DataAPIDurationComponents { throw 'stub'; } - public toDates(reference: Date | CqlTimestamp): [Date, Date] { + public toDates(reference: Date | DataAPITimestamp): [Date, Date] { if (!reference) { throw new Error('Base date is required to convert duration to date ranges'); } - if (reference instanceof CqlTimestamp) { + if (reference instanceof DataAPITimestamp) { reference = reference.toDate(); } @@ -144,31 +144,31 @@ export class CqlDuration { } } -export interface CqlTimeComponents { +export interface DataAPITimeComponents { hours: number, minutes: number, seconds: number, nanoseconds: number } -export class CqlTime { +export class DataAPITime { readonly #time: string; public [$SerializeForTable] = this.toString; - public constructor(input?: string | Date | (CqlTimeComponents & { nanoseconds?: number })) { + public constructor(input?: string | Date | (DataAPITimeComponents & { nanoseconds?: number })) { input ||= new Date(); if (typeof input === 'string') { this.#time = input; } else if (input instanceof Date) { - this.#time = CqlTime.#initTime(input.getHours(), input.getMinutes(), input.getSeconds(), input.getMilliseconds()); + this.#time = DataAPITime.#initTime(input.getHours(), input.getMinutes(), input.getSeconds(), input.getMilliseconds()); } else { - this.#time = CqlTime.#initTime(input.hours, input.minutes, input.seconds, input.nanoseconds ? input.nanoseconds.toString().padStart(9, '0') : ''); + this.#time = DataAPITime.#initTime(input.hours, input.minutes, input.seconds, input.nanoseconds ? input.nanoseconds.toString().padStart(9, '0') : ''); } Object.defineProperty(this, $CustomInspect, { - value: () => `CqlTime("${this.#time}")`, + value: () => `DataAPITime("${this.#time}")`, }); } @@ -176,7 +176,7 @@ export class CqlTime { return `${hours < 10 ? '0' : ''}${hours}:${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}${fractional ? `.${fractional}` : ''}`; } - public components(): CqlTimeComponents { + public components(): DataAPITimeComponents { const [timePart, fractionPart] = this.#time.split('.'); const [hours, mins, secs] = timePart.split(':'); @@ -188,8 +188,8 @@ export class CqlTime { }; } - public toDate(base?: Date | CqlDate | CqlTimestamp): Date { - if (base instanceof CqlTimestamp) { + public toDate(base?: Date | DataAPIDate | DataAPITimestamp): Date { + if (base instanceof DataAPITimestamp) { base = base.toDate(); } @@ -215,7 +215,7 @@ export class CqlTime { } } -export interface CqlTimestampComponents { +export interface DataAPITimestampComponents { year: number, month: number, date: number, @@ -225,12 +225,12 @@ export interface CqlTimestampComponents { nanoseconds: number } -export class CqlTimestamp { +export class DataAPITimestamp { readonly #timestamp: string; public [$SerializeForTable] = this.toString; - public constructor(input?: string | Date | Partial) { + public constructor(input?: string | Date | Partial) { input ||= new Date(); if (typeof input === 'string') { @@ -242,11 +242,11 @@ export class CqlTimestamp { } Object.defineProperty(this, $CustomInspect, { - value: () => `CqlTimestamp("${this.#timestamp}")`, + value: () => `DataAPITimestamp("${this.#timestamp}")`, }); } - public components(): CqlTimestampComponents { + public components(): DataAPITimestampComponents { const date = this.toDate(); return { year: date.getFullYear(), diff --git a/src/documents/events.ts b/src/documents/events.ts index 0fe202b6..2cd9b65a 100644 --- a/src/documents/events.ts +++ b/src/documents/events.ts @@ -28,7 +28,7 @@ import { TimeoutDescriptor } from '@/src/lib/api/timeouts'; * * @public */ -export type DataAPICommandEvents = { +export type CommandEventMap = { /** * Emitted when a command is started, before the initial HTTP request is made. */ @@ -41,6 +41,9 @@ export type DataAPICommandEvents = { * Emitted when a command has errored. */ commandFailed: (event: CommandFailedEvent) => void, + /** + * Emitted when a command has warnings. + */ commandWarnings: (event: CommandWarningsEvent) => void, } @@ -95,14 +98,22 @@ export abstract class CommandEvent extends DataAPIClientEvent { * * @internal */ - protected constructor(info: DataAPIRequestInfo) { - super(); + protected constructor(name: string, info: DataAPIRequestInfo) { + super(name); this.command = info.command; this.keyspace = info.keyspace || DEFAULT_KEYSPACE; this.source = info.collection; this.commandName = Object.keys(info.command)[0]; this.url = info.url; } + + /** + * @internal + * @protected + */ + protected _desc() { + return `(${this.keyspace}${this.source ? `.${this.source}` : ''}) ${this.commandName}`; + } } /** @@ -127,12 +138,13 @@ export class CommandStartedEvent extends CommandEvent { * @internal */ constructor(info: DataAPIRequestInfo) { - super(info); + super('CommandStarted', info); this.timeout = info.timeoutManager.initial(); } public formatted(): string { - return `[CommandStartedEvent] ${this.commandName} in ${this.keyspace}${this.source ? `.${this.source}` : ''}`; + // return `${super.formatted()}: ${this.commandName} in ${this.keyspace}${this.source ? `.${this.source}` : ''}`; + return `${super.formatted()}: ${this._desc()}`; } } @@ -163,13 +175,13 @@ export class CommandSucceededEvent extends CommandEvent { * @internal */ constructor(info: DataAPIRequestInfo, reply: RawDataAPIResponse, started: number) { - super(info); + super('CommandSucceeded', info); this.duration = performance.now() - started; this.resp = reply; } public formatted(): string { - return `[CommandSucceededEvent] ${this.commandName} in ${this.keyspace}${this.source ? `.${this.source}` : ''} (took ${this.duration}ms)`; + return `${super.formatted()}: ${this._desc()} (took ${~~this.duration}ms)`; } } @@ -202,13 +214,13 @@ export class CommandFailedEvent extends CommandEvent { * @internal */ constructor(info: DataAPIRequestInfo, error: Error, started: number) { - super(info); + super('CommandFailed', info); this.duration = performance.now() - started; this.error = error; } public formatted(): string { - return `[CommandFailedEvent] ${this.commandName} in ${this.keyspace}${this.source ? `.${this.source}` : ''} (took ${this.duration}ms) - '${this.error.message}'`; + return `${super.formatted()}: ${this._desc()} (took ${~~this.duration}ms) - '${this.error.message}'`; } } @@ -216,11 +228,11 @@ export class CommandWarningsEvent extends CommandEvent { public readonly warnings: DataAPIErrorDescriptor[]; constructor(info: DataAPIRequestInfo, warnings: DataAPIErrorDescriptor[]) { - super(info); + super('CommandWarnings', info); this.warnings = warnings; } public formatted(): string { - return `[CommandWarningsEvent] ${this.commandName} in ${this.keyspace}${this.source ? `.${this.source}` : ''} '${this.warnings.map(w => w.message).join(', ')}'`; + return `${super.formatted()}: ${this._desc()} '${this.warnings.map(w => w.message).join(', ')}'`; } } diff --git a/src/documents/tables/cursor.ts b/src/documents/tables/cursor.ts index 4892eec8..fbea870b 100644 --- a/src/documents/tables/cursor.ts +++ b/src/documents/tables/cursor.ts @@ -12,10 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { FindCursor, SomeDoc, Table } from '@/src/documents'; +import { FindCursor, SomeDoc, Table, TableFilter } from '@/src/documents'; export class TableFindCursor extends FindCursor { public override get dataSource(): Table { return super.dataSource as Table; } + + public override filter(filter: TableFilter): FindCursor { + return super.filter(filter); + } } diff --git a/src/documents/tables/ser-des.ts b/src/documents/tables/ser-des.ts index 09c0a3d5..ccd9aa0d 100644 --- a/src/documents/tables/ser-des.ts +++ b/src/documents/tables/ser-des.ts @@ -13,11 +13,11 @@ // limitations under the License. import { - CqlBlob, - CqlDate, - CqlDuration, - CqlTime, - CqlTimestamp, + DataAPIBlob, + DataAPIDate, + DataAPIDuration, + DataAPITime, + DataAPITimestamp, InetAddress, SomeDoc, SomeRow, @@ -95,7 +95,12 @@ export const mkTableSerDes = (cfg: TableSerDesConfig parseInt(n), - blob: (blob, ctx) => new CqlBlob((ctx.parsingPrimaryKey) ? { $binary: blob } : blob, false), - date: (date) => new CqlDate(date), + blob: (blob, ctx) => new DataAPIBlob((ctx.parsingPrimaryKey) ? { $binary: blob } : blob, false), + date: (date) => new DataAPIDate(date), decimal: (decimal) => (decimal instanceof BigNumber) ? decimal : new BigNumber(decimal), double: parseFloat, - duration: (duration) => new CqlDuration(duration), + duration: (duration) => new DataAPIDuration(duration), float: parseFloat, int: (n) => parseInt(n), inet: (inet) => new InetAddress(inet, null, false), smallint: (n) => parseInt(n), - time: (time) => new CqlTime(time), - timestamp: (timestamp) => new CqlTimestamp(timestamp), + time: (time) => new DataAPITime(time), + timestamp: (timestamp) => new DataAPITimestamp(timestamp), timeuuid: (uuid) => new UUID(uuid, false), tinyint: (n) => parseInt(n), uuid: (uuid) => new UUID(uuid, false), diff --git a/src/documents/tables/table.ts b/src/documents/tables/table.ts index 49b3fe2c..44eb1245 100644 --- a/src/documents/tables/table.ts +++ b/src/documents/tables/table.ts @@ -13,26 +13,24 @@ // limitations under the License. import { - CreateTableIndexOptions, - CreateTableVectorIndexOptions, - Filter, + TableCreateIndexOptions, + TableCreateVectorIndexOptions, FoundRow, KeyOf, SomeDoc, SomeRow, - TableDeleteOneOptions, + TableDeleteOneOptions, TableFilter, TableFindOneOptions, TableFindOptions, TableInsertManyError, TableInsertManyOptions, TableInsertManyResult, - TableInsertOneResult, + TableInsertOneResult, TableUpdateFilter, TableUpdateOneOptions, - UpdateFilter, } from '@/src/documents'; import { BigNumberHack, DataAPIHttpClient } from '@/src/lib/api/clients/data-api-http-client'; import { CommandImpls } from '@/src/documents/commands/command-impls'; -import { AlterTableOptions, AlterTableSchema, Db, ListTableDefinition, TableSpawnOptions } from '@/src/db'; +import { AlterTableOptions, AlterTableSchema, Db, ListTableDefinition, TableOptions } from '@/src/db'; import { DeepPartial, WithTimeout } from '@/src/lib'; import { $CustomInspect } from '@/src/lib/constants'; import { mkTableSerDes } from '@/src/documents/tables/ser-des'; @@ -84,7 +82,7 @@ export type Cols = keyof Omit; * For example: * - `'map'` is represented by a native JS `Map` * - `'vector'` is represented by an `astra-db-ts` provided `DataAPIVector` - * - `'date'` is represented by an `astra-db-ts` provided `CqlDate` + * - `'date'` is represented by an `astra-db-ts` provided `DataAPIDate` * * You may also provide your own datatypes by providing some custom serialization logic as well (see later section). * @@ -119,18 +117,18 @@ export type Cols = keyof Omit; * ```ts * interface User { *   id: string, // Partition key - *   dob: CqlDate, // Clustering (partition sort) key + *   dob: DataAPIDate, // Clustering (partition sort) key *   friends: Map, *   [$PrimaryKeyType]?: { *   id: string, - *   dob: CqlDate, + *   dob: DataAPIDate, *   }, * } * * // res.insertedId is of type { id: string } * const res = await db.table('users').insertOne({ *   id: '123', - *   dob: new CqlDate(new Date()), + *   dob: new DataAPIDate(new Date()), *   friends: new Map([['Alice', UUID.random()]]), * }); * ``` @@ -142,7 +140,7 @@ export type Cols = keyof Omit; * // equivalent to the above * interface User extends Row { *   id: string, // Partition key - *   dob: CqlDate, // Clustering (partition sort) key + *   dob: DataAPIDate, // Clustering (partition sort) key *   friends: Map, * } * ``` @@ -156,11 +154,11 @@ export type Cols = keyof Omit; * // equivalent to: * // type User = { * // id: string, - * // dob: CqlDate, + * // dob: DataAPIDate, * // friends?: Map, // Optional since it's not in the primary key * // [$PrimaryKeyType]?: { * // id: string, - * // dob: CqlDate, + * // dob: DataAPIDate, * // }, * // } * type User = InferTableSchema; @@ -187,7 +185,7 @@ export type Cols = keyof Omit; * * ###### Custom datatypes * - * You can plug in your own custom datatypes by providing some custom serialization/deserialization logic through the `serdes` option in {@link TableSpawnOptions}, {@link DbSpawnOptions} & {@link DataAPIClientOptions.dbOptions}. + * You can plug in your own custom datatypes by providing some custom serialization/deserialization logic through the `serdes` option in {@link TableOptions}, {@link DbOptions} & {@link DataAPIClientOptions.dbOptions}. * * See {@link TableSerDesConfig} for much more information, but here's a quick example: * @@ -234,7 +232,7 @@ export type Cols = keyof Omit; * @see Db.table * @see InferTableSchema * @see TableSerDesConfig - * @see TableSpawnOptions + * @see TableOptions * @see $PrimaryKeyType * * @public @@ -259,7 +257,7 @@ export class Table { * * @internal */ - constructor(db: Db, httpClient: DataAPIHttpClient, name: string, opts: TableSpawnOptions | undefined) { + constructor(db: Db, httpClient: DataAPIHttpClient, name: string, opts: TableOptions | undefined) { Object.defineProperty(this, 'name', { value: name, }); @@ -316,7 +314,7 @@ export class Table { * interface User extends Row { *   id: string, *   name: string, - *   dob?: CqlDate, + *   dob?: DataAPIDate, * } * * // res.insertedId is of type { id: string } @@ -337,27 +335,27 @@ export class Table { return this.#commands.insertMany(document, options, TableInsertManyError); } - public async updateOne(filter: Filter, update: UpdateFilter, options?: TableUpdateOneOptions): Promise { + public async updateOne(filter: TableFilter, update: TableUpdateFilter, options?: TableUpdateOneOptions): Promise { await this.#commands.updateOne(filter, update, options); } - public async deleteOne(filter: Filter, options?: TableDeleteOneOptions): Promise { + public async deleteOne(filter: TableFilter, options?: TableDeleteOneOptions): Promise { await this.#commands.deleteOne(filter, options); } - public async deleteMany(filter: Filter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise { + public async deleteMany(filter: TableFilter, options?: WithTimeout<'generalMethodTimeoutMs'>): Promise { await this.#commands.deleteMany(filter, options); } - public find(filter: Filter, options?: TableFindOptions & { projection?: never }): TableFindCursor, FoundRow> + public find(filter: TableFilter, options?: TableFindOptions & { projection?: never }): TableFindCursor, FoundRow> - public find>(filter: Filter, options: TableFindOptions): TableFindCursor, FoundRow> + public find>(filter: TableFilter, options: TableFindOptions): TableFindCursor, FoundRow> - public find(filter: Filter, options?: TableFindOptions): TableFindCursor { + public find(filter: TableFilter, options?: TableFindOptions): TableFindCursor { return this.#commands.find(filter, options, TableFindCursor); } - public async findOne(filter: Filter, options?: TableFindOneOptions): Promise | null> { + public async findOne(filter: TableFilter, options?: TableFindOneOptions): Promise | null> { return this.#commands.findOne(filter, options); } @@ -377,16 +375,16 @@ export class Table { return this; } - public async createIndex(name: string, column: Cols | string, options?: CreateTableIndexOptions): Promise { + public async createIndex(name: string, column: Cols | string, options?: TableCreateIndexOptions): Promise { await this.#httpClient.executeCommand({ createIndex: { name: name, definition: { column, options: { - caseSensitive: options?.caseSensitive, - normalize: options?.normalize, - ascii: options?.ascii, + caseSensitive: options?.options?.caseSensitive, + normalize: options?.options?.normalize, + ascii: options?.options?.ascii, }, }, options: { @@ -398,15 +396,15 @@ export class Table { }); } - public async createVectorIndex(name: string, column: Cols | string, options?: CreateTableVectorIndexOptions): Promise { + public async createVectorIndex(name: string, column: Cols | string, options?: TableCreateVectorIndexOptions): Promise { await this.#httpClient.executeCommand({ createVectorIndex: { name: name, definition: { column, options: { - sourceModel: options?.sourceModel, - metric: options?.metric, + sourceModel: options?.options?.sourceModel, + metric: options?.options?.metric, }, }, options: { diff --git a/src/documents/tables/types/filter.ts b/src/documents/tables/types/filter.ts new file mode 100644 index 00000000..a899c338 --- /dev/null +++ b/src/documents/tables/types/filter.ts @@ -0,0 +1,70 @@ +// Copyright DataStax, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { SomeRow } from '@/src/documents'; + +/** + * Represents some filter operation for a given document schema. + * + * @example + * ```typescript + * interface BasicSchema { + *   arr: string[], + *   num: number, + * } + * + * db.Tables('coll_name').findOne({ + *   $and: [ + *   { _id: { $in: ['abc', 'def'] } }, + *   { $not: { arr: { $size: 0 } } }, + *   ] + * }); + * ``` + * + * @public + */ +export type TableFilter = { + [K in keyof Schema]?: TableFilterExpr +} & { + $and?: TableFilter[], + $or?: TableFilter[], + $not?: TableFilter, +} & { + [key: string]: any, +} + +/** + * Represents an expression in a filter statement, such as an exact value, or a filter operator + * + * @public + */ +export type TableFilterExpr = Elem | TableFilterOps; + +/** + * Represents filter operators such as `$eq` and `$in` (but not statements like `$and`) + * + * @public + */ +export type TableFilterOps = { + $eq?: Elem, + $ne?: Elem, + $in?: Elem[], + $nin?: Elem[] /* I can't un-see this as 'Nine-Inch Nails'... */, + $exists?: boolean, + $lt?: Elem, + $lte?: Elem, + $gt?: Elem, + $gte?: Elem, + [key: string]: any, +} diff --git a/src/documents/tables/types/index.ts b/src/documents/tables/types/index.ts index 44411251..dd1cc185 100644 --- a/src/documents/tables/types/index.ts +++ b/src/documents/tables/types/index.ts @@ -17,9 +17,12 @@ export type * from './find/find'; export type * from './find/find-one'; export type * from './indexes/create-index'; export type * from './indexes/create-vector-index'; +export type * from './indexes/drop-index'; export type * from './insert/insert-many'; export type * from './insert/insert-one'; export type * from './update/update-many'; export type * from './update/update-one'; export type * from './row'; export type * from './utils'; +export type * from './filter'; +export type * from './update-filter'; diff --git a/src/documents/tables/types/indexes/create-index.ts b/src/documents/tables/types/indexes/create-index.ts index 71934ed3..91da459d 100644 --- a/src/documents/tables/types/indexes/create-index.ts +++ b/src/documents/tables/types/indexes/create-index.ts @@ -14,9 +14,11 @@ import { WithTimeout } from '@/src/lib'; -export interface CreateTableIndexOptions extends WithTimeout<'tableAdminTimeoutMs'> { - caseSensitive?: boolean, - normalize?: boolean, - ascii?: boolean, +export interface TableCreateIndexOptions extends WithTimeout<'tableAdminTimeoutMs'> { + options?: { + caseSensitive?: boolean, + normalize?: boolean, + ascii?: boolean, + }; ifNotExists?: boolean, } diff --git a/src/documents/tables/types/indexes/create-vector-index.ts b/src/documents/tables/types/indexes/create-vector-index.ts index 2b67fe50..7e11b02e 100644 --- a/src/documents/tables/types/indexes/create-vector-index.ts +++ b/src/documents/tables/types/indexes/create-vector-index.ts @@ -14,8 +14,10 @@ import { WithTimeout } from '@/src/lib'; -export interface CreateTableVectorIndexOptions extends WithTimeout<'tableAdminTimeoutMs'> { - metric: 'cosine' | 'euclidean' | 'dot_product', - sourceModel?: string, +export interface TableCreateVectorIndexOptions extends WithTimeout<'tableAdminTimeoutMs'> { + options?: { + metric: 'cosine' | 'euclidean' | 'dot_product', + sourceModel?: string, + } ifNotExists?: boolean, } diff --git a/src/documents/tables/types/indexes/drop-index.ts b/src/documents/tables/types/indexes/drop-index.ts new file mode 100644 index 00000000..e35151a2 --- /dev/null +++ b/src/documents/tables/types/indexes/drop-index.ts @@ -0,0 +1,19 @@ +// Copyright DataStax, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { WithTimeout } from '@/src/lib'; + +export interface TableDropIndexOptions extends WithTimeout<'tableAdminTimeoutMs'> { + ifExists?: boolean, +} diff --git a/src/documents/tables/types/row.ts b/src/documents/tables/types/row.ts index e8744b10..2e723a92 100644 --- a/src/documents/tables/types/row.ts +++ b/src/documents/tables/types/row.ts @@ -82,15 +82,15 @@ export type SomeRow = Record; * * @example * ```ts - * import { $PrimaryKeyType, CqlDate, UUID } from '@datastax/astra-db-ts'; + * import { $PrimaryKeyType, DataAPIDate, UUID } from '@datastax/astra-db-ts'; * * interface User { *   id: string, // Partition key - *   dob: CqlDate, // Clustering (partition sort) key + *   dob: DataAPIDate, // Clustering (partition sort) key *   friends: Map, *   [$PrimaryKeyType]?: { *     id: string, - *     dob: CqlDate, + *     dob: DataAPIDate, *   }, * } * @@ -98,12 +98,12 @@ export type SomeRow = Record; * * const resp = await table.insertOne({ *   id: 'user1', - *   dob: new CqlDate('1990-01-01'), + *   dob: new DataAPIDate('1990-01-01'), *   friends: new Map(), // he's a loner :( * }); * * console.log(resp.insertedId.id); // 'user1' - * console.log(resp.insertedId.dob); // CqlDate("1990-01-01") + * console.log(resp.insertedId.dob); // DataAPIDate("1990-01-01") * ``` * * @see Row @@ -141,21 +141,21 @@ export declare const $PrimaryKeyType: '$PrimaryKeyType'; * * @example * ```ts - * import { Row, CqlDate, UUID } from '@datastax/astra-db-ts'; + * import { Row, DataAPIDate, UUID } from '@datastax/astra-db-ts'; * * // equivalent to: * // interface User { * // id: string, // Partition key - * // dob: CqlDate, // Clustering (partition sort) key + * // dob: DataAPIDate, // Clustering (partition sort) key * // friends: Map, * // [$PrimaryKeyType]?: { * // id: string, - * // dob: CqlDate, + * // dob: DataAPIDate, * // }, * // } * interface User extends Row { *   id: string, // Partition key - *   dob: CqlDate, // Clustering (partition sort) key + *   dob: DataAPIDate, // Clustering (partition sort) key *   friends: Map, * } * @@ -163,12 +163,12 @@ export declare const $PrimaryKeyType: '$PrimaryKeyType'; * * const resp = await table.insertOne({ *   id: 'user1', - *   dob: new CqlDate('1990-01-01'), + *   dob: new DataAPIDate('1990-01-01'), *   friends: new Map(), // he's a loner :( * }); * * console.log(resp.insertedId.id); // 'user1' - * console.log(resp.insertedId.dob); // CqlDate("1990-01-01") + * console.log(resp.insertedId.dob); // DataAPIDate("1990-01-01") * ``` * * @see Table diff --git a/src/documents/tables/types/update-filter.ts b/src/documents/tables/types/update-filter.ts new file mode 100644 index 00000000..f0ec0495 --- /dev/null +++ b/src/documents/tables/types/update-filter.ts @@ -0,0 +1,64 @@ +// Copyright DataStax, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { SomeRow } from '@/src/documents'; + +/** + * Represents the update filter to specify how to update a document. + * + * @example + * ```typescript + * const updateFilter: TableUpdateFilter = { + *   $set: { + *   'customer': 'Jim B.' + *   }, + *   $unset: { + *   'customer': '' + *   }, + * } + * ``` + * + * @field $set - Set the value of a field in the document. + * @field $unset - Remove the field from the document. + * + * @public + */ +export interface TableUpdateFilter { + /** + * Set the value of a field in the document. + * + * @example + * ```typescript + * const updateFilter: UpdateFilter = { + *   $set: { + *   'customer.name': 'Jim B.' + *   } + * } + * ``` + */ + $set?: Partial & SomeRow, + /** + * Remove the field from the document. + * + * @example + * ```typescript + * const updateFilter: UpdateFilter = { + *   $unset: { + *   'customer.phone': '' + *   } + * } + * ``` + */ + $unset?: Record, +} diff --git a/src/documents/tables/types/utils.ts b/src/documents/tables/types/utils.ts index 879d8668..9ec4cc79 100644 --- a/src/documents/tables/types/utils.ts +++ b/src/documents/tables/types/utils.ts @@ -83,12 +83,12 @@ export type FoundRow = Omit, '$similarity'> & { $similarity?: * ```ts * interface User extends Row { *   id: string, // Partition key - *   dob: CqlDate, // Clustering (partition sort) key + *   dob: DataAPIDate, // Clustering (partition sort) key *   friends: Map, * } * * // equivalent to: - * // type UserKey = { id: string, dob: CqlDate }; + * // type UserKey = { id: string, dob: DataAPIDate }; * type UserKey = KeyOf; * ``` * diff --git a/src/documents/types/common.ts b/src/documents/types/common.ts index d5f8fba3..2f5cfcb4 100644 --- a/src/documents/types/common.ts +++ b/src/documents/types/common.ts @@ -87,7 +87,7 @@ export type Sort = Record; +export type Projection = Record; /** * Specifies the sort criteria for selecting documents. diff --git a/src/documents/collections/types/dot-notation.ts b/src/documents/types/dot-notation.ts similarity index 100% rename from src/documents/collections/types/dot-notation.ts rename to src/documents/types/dot-notation.ts diff --git a/src/documents/types/filters.ts b/src/documents/types/filters.ts new file mode 100644 index 00000000..1790500d --- /dev/null +++ b/src/documents/types/filters.ts @@ -0,0 +1,16 @@ +// Copyright DataStax, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export type Filter = Record; +export type UpdateFilter = Record; diff --git a/src/documents/types/index.ts b/src/documents/types/index.ts index 067a74f0..12c51ab6 100644 --- a/src/documents/types/index.ts +++ b/src/documents/types/index.ts @@ -13,3 +13,4 @@ // limitations under the License. export type * from './common'; +export type * from './filters'; diff --git a/src/lib/api/clients/data-api-http-client.ts b/src/lib/api/clients/data-api-http-client.ts index 87e946a0..7d23734a 100644 --- a/src/lib/api/clients/data-api-http-client.ts +++ b/src/lib/api/clients/data-api-http-client.ts @@ -26,16 +26,19 @@ import { import type { HeaderProvider, HTTPClientOptions, KeyspaceRef } from '@/src/lib/api/clients/types'; import { HttpClient } from '@/src/lib/api/clients/http-client'; import { DEFAULT_DATA_API_AUTH_HEADER, HttpMethods } from '@/src/lib/api/constants'; -import { CollectionSpawnOptions, TableSpawnOptions } from '@/src/db'; -import type { AdminSpawnOptions } from '@/src/client'; +import { CollectionOptions, TableOptions } from '@/src/db'; +import type { AdminOptions } from '@/src/client'; import { isNullish } from '@/src/lib/utils'; import { mkRespErrorFromResponse } from '@/src/documents/errors'; import { TimeoutManager, Timeouts } from '@/src/lib/api/timeouts'; +import { EmptyObj } from '@/src/lib/types'; + +type ClientKind = 'admin' | 'normal'; /** * @internal */ -type ExecuteCommandOptions = { +type ExecCmdOpts = (Kind extends 'admin' ? { methodName: string } : EmptyObj) & { keyspace?: string | null, timeoutManager: TimeoutManager, bigNumsPresent?: boolean, @@ -54,14 +57,19 @@ export interface DataAPIRequestInfo { bigNumsPresent: boolean | undefined, } -type EmissionStrategy = (logger: Logger) => { - emitCommandStarted?(info: DataAPIRequestInfo): void, - emitCommandFailed?(info: DataAPIRequestInfo, error: Error, started: number): void, - emitCommandSucceeded?(info: DataAPIRequestInfo, resp: RawDataAPIResponse, started: number): void, - emitCommandWarnings?(info: DataAPIRequestInfo, warnings: DataAPIErrorDescriptor[]): void, +type EmissionStrategy = (logger: Logger) => { + emitCommandStarted?(info: DataAPIRequestInfo, opts: ExecCmdOpts): void, + emitCommandFailed?(info: DataAPIRequestInfo, error: Error, started: number, opts: ExecCmdOpts): void, + emitCommandSucceeded?(info: DataAPIRequestInfo, resp: RawDataAPIResponse, started: number, opts: ExecCmdOpts): void, + emitCommandWarnings?(info: DataAPIRequestInfo, warnings: DataAPIErrorDescriptor[], opts: ExecCmdOpts): void, +} + +type EmissionStrategies = { + Normal: EmissionStrategy<'normal'>, + Admin: EmissionStrategy<'admin'>, } -export const EmissionStrategy: Record<'Normal' | 'Admin', EmissionStrategy> = { +export const EmissionStrategy: EmissionStrategies = { Normal: (logger) => ({ emitCommandStarted: logger.commandStarted, emitCommandFailed: logger.commandFailed, @@ -69,34 +77,34 @@ export const EmissionStrategy: Record<'Normal' | 'Admin', EmissionStrategy> = { emitCommandWarnings: logger.commandWarnings, }), Admin: (logger) => ({ - emitCommandStarted(info) { - logger.adminCommandStarted?.(adaptInfo4Devops(info), true, null!); // TODO + emitCommandStarted(info, opts) { + logger.adminCommandStarted?.(adaptInfo4Devops(info, opts.methodName), true, null!); // TODO }, - emitCommandFailed(info, error, started) { - logger.adminCommandFailed?.(adaptInfo4Devops(info), true, error, started); + emitCommandFailed(info, error, started, opts) { + logger.adminCommandFailed?.(adaptInfo4Devops(info, opts.methodName), true, error, started); }, - emitCommandSucceeded(info, resp, started) { - logger.adminCommandSucceeded?.(adaptInfo4Devops(info), true, resp, started); + emitCommandSucceeded(info, resp, started, opts) { + logger.adminCommandSucceeded?.(adaptInfo4Devops(info, opts.methodName), true, resp, started); }, - emitCommandWarnings(info, warnings) { - logger.adminCommandWarnings?.(adaptInfo4Devops(info), true, warnings); + emitCommandWarnings(info, warnings, opts) { + logger.adminCommandWarnings?.(adaptInfo4Devops(info, opts.methodName), true, warnings); }, }), }; -const adaptInfo4Devops = (info: DataAPIRequestInfo) => ({ +const adaptInfo4Devops = (info: DataAPIRequestInfo, methodName: string) => ({ method: 'POST', data: info.command, path: info.url, - params: {}, + methodName, }); /** * @internal */ -interface DataAPIHttpClientOpts extends HTTPClientOptions { +interface DataAPIHttpClientOpts extends HTTPClientOptions { keyspace: KeyspaceRef, - emissionStrategy: EmissionStrategy, + emissionStrategy: EmissionStrategy, embeddingHeaders: EmbeddingHeadersProvider, tokenProvider: TokenProvider | undefined, } @@ -112,25 +120,26 @@ export interface BigNumberHack { /** * @internal */ -export class DataAPIHttpClient extends HttpClient { +export class DataAPIHttpClient extends HttpClient { public collection?: string; public keyspace: KeyspaceRef; - public emissionStrategy: ReturnType; + public emissionStrategy: ReturnType>; public bigNumHack?: BigNumberHack; - readonly #props: DataAPIHttpClientOpts; + readonly #props: DataAPIHttpClientOpts; - constructor(props: DataAPIHttpClientOpts) { + constructor(props: DataAPIHttpClientOpts) { super(props, [mkAuthHeaderProvider(props.tokenProvider), () => props.embeddingHeaders.getHeaders()], DataAPITimeoutError.mk); this.keyspace = props.keyspace; this.#props = props; this.emissionStrategy = props.emissionStrategy(this.logger); } - public forTableSlashCollectionOrWhateverWeWouldCallTheUnionOfTheseTypes(keyspace: string, collection: string, opts: CollectionSpawnOptions | TableSpawnOptions | undefined, bigNumHack: BigNumberHack): DataAPIHttpClient { + public forTableSlashCollectionOrWhateverWeWouldCallTheUnionOfTheseTypes(keyspace: string, collection: string, opts: CollectionOptions | TableOptions | undefined, bigNumHack: BigNumberHack): DataAPIHttpClient { const clone = new DataAPIHttpClient({ ...this.#props, embeddingHeaders: EmbeddingHeadersProvider.parseHeaders(opts?.embeddingApiKey), logging: Logger.advanceConfig(this.#props.logging, opts?.logging), + emissionStrategy: EmissionStrategy.Normal, keyspace: { ref: keyspace }, }); @@ -141,7 +150,7 @@ export class DataAPIHttpClient extends HttpClient { return clone; } - public forDbAdmin(opts: AdminSpawnOptions | undefined): DataAPIHttpClient { + public forDbAdmin(opts: AdminOptions | undefined): DataAPIHttpClient<'admin'> { const clone = new DataAPIHttpClient({ ...this.#props, tokenProvider: TokenProvider.parseToken([opts?.adminToken, this.#props.tokenProvider], 'admin token'), @@ -149,28 +158,26 @@ export class DataAPIHttpClient extends HttpClient { baseUrl: opts?.endpointUrl ?? this.#props.baseUrl, baseApiPath: opts?.endpointUrl ? '' : this.#props.baseApiPath, additionalHeaders: { ...this.#props.additionalHeaders, ...opts?.additionalHeaders }, + emissionStrategy: EmissionStrategy.Admin, }); clone.collection = undefined; - clone.emissionStrategy = EmissionStrategy.Admin(clone.logger); clone.tm = new Timeouts(DataAPITimeoutError.mk, { ...this.tm.baseTimeouts, ...opts?.timeoutDefaults }); return clone; } - public async executeCommand(command: Record, options: ExecuteCommandOptions) { - return await this._requestDataAPI({ + public async executeCommand(command: Record, options: ExecCmdOpts): Promise { + let started = 0; + + const info: DataAPIRequestInfo = { url: this.baseUrl, - timeoutManager: options.timeoutManager, - collection: options?.collection, - keyspace: options?.keyspace, + collection: options.collection, + keyspace: options.keyspace, command: command, - bigNumsPresent: options?.bigNumsPresent, - }); - } - - private async _requestDataAPI(info: DataAPIRequestInfo): Promise { - let started = 0; + timeoutManager: options.timeoutManager, + bigNumsPresent: options.bigNumsPresent, + }; try { info.collection ||= this.collection; @@ -188,15 +195,15 @@ export class DataAPIHttpClient extends HttpClient { info.url += keyspacePath + collectionPath; started = performance.now(); - this.emissionStrategy.emitCommandStarted?.(info); + this.emissionStrategy.emitCommandStarted?.(info, options); - const command = (info.bigNumsPresent) + const serialized = (info.bigNumsPresent) ? this.bigNumHack?.parser.stringify(info.command) : JSON.stringify(info.command); const resp = await this._request({ url: info.url, - data: command, + data: serialized, timeoutManager: info.timeoutManager, method: HttpMethods.Post, }); @@ -214,7 +221,7 @@ export class DataAPIHttpClient extends HttpClient { const warnings = data?.status?.warnings ?? []; if (warnings.length) { - this.emissionStrategy.emitCommandWarnings?.(info, warnings); + this.emissionStrategy.emitCommandWarnings?.(info, warnings, options); } delete data?.status?.warnings; @@ -228,10 +235,10 @@ export class DataAPIHttpClient extends HttpClient { errors: data.errors, }; - this.emissionStrategy.emitCommandSucceeded?.(info, respData, started); + this.emissionStrategy.emitCommandSucceeded?.(info, respData, started, options); return respData; } catch (e: any) { - this.emissionStrategy.emitCommandFailed?.(info, e, started); + this.emissionStrategy.emitCommandFailed?.(info, e, started, options); throw e; } } diff --git a/src/lib/api/clients/devops-api-http-client.ts b/src/lib/api/clients/devops-api-http-client.ts index 289fc0b5..7f26bdc2 100644 --- a/src/lib/api/clients/devops-api-http-client.ts +++ b/src/lib/api/clients/devops-api-http-client.ts @@ -30,6 +30,7 @@ export interface DevOpsAPIRequestInfo { method: HttpMethodStrings, data?: Record, params?: Record, + methodName: string, } interface LongRunningRequestInfo { @@ -143,6 +144,7 @@ export class DevOpsAPIHttpClient extends HttpClient { const resp = await this.request({ method: HttpMethods.Get, path: `/databases/${id}`, + methodName: req.methodName, }, info.timeoutManager, started); if (resp.data?.status === info.target) { diff --git a/src/lib/api/clients/http-client.ts b/src/lib/api/clients/http-client.ts index 3c1ac20a..c62eb0f8 100644 --- a/src/lib/api/clients/http-client.ts +++ b/src/lib/api/clients/http-client.ts @@ -17,7 +17,7 @@ import type { Caller } from '@/src/client'; import type TypedEmitter from 'typed-emitter'; import type { FetchCtx, FetcherResponseInfo } from '@/src/lib/api/fetch/types'; import type { HeaderProvider, HTTPClientOptions, HTTPRequestInfo } from '@/src/lib/api/clients'; -import type { DataAPIClientEvents } from '@/src/lib/logging'; +import type { DataAPIClientEventMap } from '@/src/lib/logging'; import { Logger } from '@/src/lib/logging/logger'; import { OneOrMany } from '@/src/lib/types'; import { MkTimeoutError, Timeouts } from '@/src/lib/api/timeouts'; @@ -27,7 +27,7 @@ import { MkTimeoutError, Timeouts } from '@/src/lib/api/timeouts'; */ export abstract class HttpClient { readonly baseUrl: string; - readonly emitter: TypedEmitter; + readonly emitter: TypedEmitter; readonly logger: Logger; readonly fetchCtx: FetchCtx; readonly baseHeaders: Record; diff --git a/src/lib/api/clients/types.ts b/src/lib/api/clients/types.ts index 1e286393..9e5dc0ed 100644 --- a/src/lib/api/clients/types.ts +++ b/src/lib/api/clients/types.ts @@ -13,7 +13,7 @@ // limitations under the License. import type TypedEmitter from 'typed-emitter'; -import type { DataAPICommandEvents } from '@/src/documents'; +import type { CommandEventMap } from '@/src/documents'; import type { FetchCtx } from '@/src/lib/api/fetch/types'; import type { HttpMethods } from '@/src/lib/api/constants'; import type { Ref } from '@/src/lib/types'; @@ -26,7 +26,7 @@ import { TimeoutDescriptor, TimeoutManager } from '@/src/lib/api/timeouts'; export interface HTTPClientOptions { baseUrl: string, baseApiPath?: string | null, - emitter: TypedEmitter, + emitter: TypedEmitter, logging: NormalizedLoggingConfig[] | undefined, fetchCtx: FetchCtx, userAgent: string, diff --git a/src/lib/logging/constants.ts b/src/lib/logging/constants.ts index 3fa5c88b..e06873fd 100644 --- a/src/lib/logging/constants.ts +++ b/src/lib/logging/constants.ts @@ -14,7 +14,7 @@ // noinspection DuplicatedCode import { EqualityProof } from '@/src/lib/validation'; -import type { DataAPIClientEvents, DataAPILoggingEvent, DataAPILoggingOutput } from '@/src/lib'; +import type { DataAPIClientEventMap, DataAPILoggingEvent, DataAPILoggingOutput } from '@/src/lib'; import { CommandFailedEvent, CommandStartedEvent, CommandSucceededEvent, CommandWarningsEvent } from '@/src/documents'; import { AdminCommandFailedEvent, @@ -27,13 +27,26 @@ import { buildOutputsMap } from '@/src/lib/logging/util'; import type { InternalLoggingConfig } from '@/src/client/types/internal'; import type { NormalizedLoggingConfig } from '@/src/lib/logging/types'; +/** + * @internal + */ export const LoggingEvents = ['all', 'adminCommandStarted', 'adminCommandPolling', 'adminCommandSucceeded', 'adminCommandFailed', 'adminCommandWarnings', 'commandStarted', 'commandFailed', 'commandSucceeded', 'commandWarnings']; + +/** + * @internal + */ export const LoggingEventsWithoutAll = LoggingEvents.filter((e) => e !== 'all'); void EqualityProof; +/** + * @internal + */ export const LoggingOutputs = ['event', 'stdout', 'stderr']; void EqualityProof; +/** + * @internal + */ export const EventConstructors = { commandFailed: CommandFailedEvent, commandStarted: CommandStartedEvent, @@ -44,11 +57,17 @@ export const EventConstructors = { adminCommandPolling: AdminCommandPollingEvent, adminCommandWarnings: AdminCommandWarningsEvent, adminCommandSucceeded: AdminCommandSucceededEvent, -} satisfies Record; +} satisfies Record; +/** + * @internal + */ export const EmptyInternalLoggingConfig = Object.fromEntries(LoggingEventsWithoutAll.map((e) => [e, buildOutputsMap([])])) as InternalLoggingConfig; -export const EventLoggingOutputDefaults = { +/** + * @internal + */ +export const DataAPILoggingDefaultOutputs = { adminCommandStarted: ['event', 'stdout'], adminCommandPolling: ['event', 'stdout'], adminCommandSucceeded: ['event', 'stdout'], @@ -60,7 +79,7 @@ export const EventLoggingOutputDefaults = { commandWarnings: ['event', 'stderr'], }; -export const EventLoggingDefaults: NormalizedLoggingConfig[] = [{ +export const DataAPILoggingDefaults: NormalizedLoggingConfig[] = [{ events: ['adminCommandStarted', 'adminCommandPolling', 'adminCommandSucceeded'], emits: ['event', 'stdout'], }, { diff --git a/src/lib/logging/events.ts b/src/lib/logging/events.ts index 0a607646..420a78ff 100644 --- a/src/lib/logging/events.ts +++ b/src/lib/logging/events.ts @@ -21,8 +21,29 @@ * @public */ export abstract class DataAPIClientEvent { + /** + * The name of the event. + */ + public readonly name: string; + + /** + * Should not be instantiated directly. + * + * @internal + */ + protected constructor(name: string) { + this.name = name; + } + /** * Returns the event in a formatted string, as it would be logged to stdout/stderr (if enabled). */ - public abstract formatted(): string; + public formatted(): string { + return `${DataAPIClientEvent.formattedPrefix()}[${this.name}]`; + } + + public static formattedPrefix(): string { + const date = new Date(); + return `${date.getUTCFullYear()}-${(date.getUTCMonth() + 1).toString().padStart(2, '0')}-${date.getUTCDate().toString().padStart(2, '0')} ${date.getUTCHours().toString().padStart(2, '0')}:${date.getUTCMinutes().toString().padStart(2, '0')}:${date.getUTCSeconds().toString().padStart(2, '0')}Z `; + } } diff --git a/src/lib/logging/index.ts b/src/lib/logging/index.ts index 8a656a92..eb6bd0f5 100644 --- a/src/lib/logging/index.ts +++ b/src/lib/logging/index.ts @@ -14,5 +14,5 @@ // noinspection DuplicatedCode export type * from './types'; -export { EventLoggingDefaults } from './constants'; +export { DataAPILoggingDefaults } from './constants'; export * from './events'; diff --git a/src/lib/logging/logger.ts b/src/lib/logging/logger.ts index 1f80e3df..f159b104 100644 --- a/src/lib/logging/logger.ts +++ b/src/lib/logging/logger.ts @@ -14,7 +14,7 @@ // noinspection DuplicatedCode import type { InternalLoggingConfig } from '@/src/client/types/internal'; -import type { DataAPIClientEvents, DataAPILoggingConfig, NormalizedLoggingConfig } from '@/src/lib/logging/types'; +import type { DataAPIClientEventMap, DataAPILoggingConfig, NormalizedLoggingConfig } from '@/src/lib/logging/types'; import type { CommandFailedEvent, CommandStartedEvent, CommandSucceededEvent, CommandWarningsEvent } from '@/src/documents'; import type { AdminCommandFailedEvent, @@ -26,8 +26,8 @@ import type { import { EmptyInternalLoggingConfig, EventConstructors, - EventLoggingDefaults, - EventLoggingOutputDefaults, + DataAPILoggingDefaults, + DataAPILoggingDefaultOutputs, LoggingEventsWithoutAll, } from '@/src/lib/logging/constants'; import { buildOutputsMap } from '@/src/lib/logging/util'; @@ -40,7 +40,10 @@ interface ConsoleLike { error: (...args: any[]) => void; } -export class Logger implements Partial> { +/** + * @internal + */ +export class Logger implements Partial> { public commandStarted?: (...args: ConstructorParameters ) => void; public commandFailed?: (...args: ConstructorParameters ) => void; public commandWarnings?: (...args: ConstructorParameters ) => void; @@ -51,11 +54,11 @@ export class Logger implements Partial ) => void; public adminCommandSucceeded?: (...args: ConstructorParameters) => void; - constructor(_config: NormalizedLoggingConfig[] | undefined, private emitter: TypedEventEmitter, private console: ConsoleLike) { + constructor(_config: NormalizedLoggingConfig[] | undefined, private emitter: TypedEventEmitter, private console: ConsoleLike) { const config = Logger.buildInternalConfig(_config); for (const [_event, outputs] of Object.entries(config)) if (outputs) { - const event = _event as keyof DataAPIClientEvents; + const event = _event as keyof DataAPIClientEventMap; this[event] = (...args: any[]) => { const eventClass = new (EventConstructors[event])(...args) as DataAPIClientEvent; @@ -91,20 +94,20 @@ export class Logger implements Partial { if (c === 'all') { - return EventLoggingDefaults; + return DataAPILoggingDefaults; } if (typeof c === 'string') { - return [{ events: [c], emits: EventLoggingOutputDefaults[c] }]; + return [{ events: [c], emits: DataAPILoggingDefaultOutputs[c] }]; } if (c.events === 'all' || Array.isArray(c.events) && c.events.includes('all')) { @@ -125,7 +128,7 @@ export class Logger implements Partial('DataAPILoggingEvent', LoggingEvents, true); const parseLoggingOutput = p.mkStrEnumParser('DataAPILoggingOutput', LoggingOutputs, true); +/** + * @internal + */ export const parseLoggingConfig: Parser = (config, field) => { if (isNullish(config)) { return undefined; diff --git a/src/lib/logging/types.ts b/src/lib/logging/types.ts index 79ea38f7..7ac13d89 100644 --- a/src/lib/logging/types.ts +++ b/src/lib/logging/types.ts @@ -13,8 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { DataAPICommandEvents } from '@/src/documents'; -import { AdminCommandEvents } from '@/src/administration'; +import { CommandEventMap } from '@/src/documents'; +import { AdminCommandEventMap } from '@/src/administration'; import { OneOrMany } from '@/src/lib/types'; // noinspection ES6UnusedImports import TypedEventEmitter from 'typed-emitter'; @@ -41,7 +41,7 @@ import TypedEventEmitter from 'typed-emitter'; * - You can't programmatically interact with the logs/data * - You can't easily filter or format the logs * - * {@link DataAPIClientEvents} are a more flexible way to interact with the logs, allowing you to basically plug in, or + * {@link DataAPIClientEventMap} are a more flexible way to interact with the logs, allowing you to basically plug in, or * even build, your own logging system around them. * * And of course, you're free to use both events and console logging in tandem, if you so choose. @@ -56,9 +56,9 @@ import TypedEventEmitter from 'typed-emitter'; * #### Event types * * There are two major categories of events emitted by the {@link DataAPIClient}: - * - {@link DataAPICommandEvents} - Events related to the execution of a command + * - {@link CommandEventMap} - Events related to the execution of a command * - i.e. `Db`, `Collection`, `Table` operations - * - {@link AdminCommandEvents} - Events related to the execution of an admin command + * - {@link AdminCommandEventMap} - Events related to the execution of an admin command * - i.e. `AstraAdmin`, `DbAdmin` operations * * Every event may be enabled/disabled individually, independent of one another. @@ -173,14 +173,14 @@ import TypedEventEmitter from 'typed-emitter'; * ``` * * @see DataAPILoggingConfig - * @see DataAPICommandEvents - * @see AdminCommandEvents + * @see CommandEventMap + * @see AdminCommandEventMap * * @public */ -export type DataAPIClientEvents = - & DataAPICommandEvents - & AdminCommandEvents; +export type DataAPIClientEventMap = + & AdminCommandEventMap + & CommandEventMap; /** * #### Overview @@ -219,7 +219,7 @@ export type DataAPIClientEvents = * * #### Event types * - * See {@link DataAPIClientEvents} for more information on the types of events emitted. + * See {@link DataAPIClientEventMap} for more information on the types of events emitted. * * #### Output types * @@ -233,7 +233,7 @@ export type DataAPIClientEvents = * * ```ts * const client = new DataAPIClient('*TOKEN*', { - * logging: [{ events: 'all', emit: 'stdout' }], + * logging: [{ events: 'all', emits: 'stdout' }], * }); * const db = client.db('*ENDPOINT*'); * @@ -243,7 +243,7 @@ export type DataAPIClientEvents = * await db.createCollection('my_collection'); * ``` * - * @see DataAPIClientEvents + * @see DataAPIClientEventMap * @see DataAPILoggingEvent * @see DataAPILoggingOutput * @@ -255,11 +255,11 @@ export type DataAPILoggingConfig = DataAPILoggingEvent | readonly (DataAPILoggin * Represents the different events that can be emitted/logged by the {@link DataAPIClient}, as well as the convenient * shorthand 'all' to configure all events at once. * - * See {@link DataAPIClientEvents} & {@link DataAPILoggingConfig} for much more info. + * See {@link DataAPIClientEventMap} & {@link DataAPILoggingConfig} for much more info. * * @public */ -export type DataAPILoggingEvent = 'all' | keyof DataAPIClientEvents; +export type DataAPILoggingEvent = 'all' | keyof DataAPIClientEventMap; /** * Represents the different outputs that can be emitted/logged to by the {@link DataAPIClient}. @@ -267,7 +267,7 @@ export type DataAPILoggingEvent = 'all' | keyof DataAPIClientEvents; * This can be set to either 'event', 'stdout', or 'stderr'. However, attempting to set both 'stdout' and 'stderr' * as an output for a single event will result in an error. * - * See {@link DataAPIClientEvents} & {@link DataAPILoggingConfig} for much more info. + * See {@link DataAPIClientEventMap} & {@link DataAPILoggingConfig} for much more info. * * @public */ @@ -278,7 +278,7 @@ export type DataAPILoggingOutput = 'event' | 'stdout' | 'stderr'; * * Settings the `emits` field to `[]` will disable logging for the specified events. * - * See {@link DataAPIClientEvents} & {@link DataAPILoggingConfig} for much more info. + * See {@link DataAPIClientEventMap} & {@link DataAPILoggingConfig} for much more info. * * @public */ diff --git a/src/lib/logging/util.ts b/src/lib/logging/util.ts index 6fbefd9b..d8f88a8f 100644 --- a/src/lib/logging/util.ts +++ b/src/lib/logging/util.ts @@ -15,6 +15,9 @@ import { DataAPILoggingOutput } from '@/src/lib/logging/types'; +/** + * @internal + */ export const buildOutputsMap = (emits: readonly DataAPILoggingOutput[]) => (emits.length === 0) ? undefined : ({ diff --git a/tests/integration/client/data-api-client.test.ts b/tests/integration/client/data-api-client.test.ts index b37e817a..3e4114a5 100644 --- a/tests/integration/client/data-api-client.test.ts +++ b/tests/integration/client/data-api-client.test.ts @@ -183,8 +183,8 @@ describe('integration.client.data-api-client', () => { assert.ok(succeededEvents[0].resp?.status?.insertedIds instanceof Array); assert.ok(typeof succeededEvents[1].resp?.status?.deletedCount === 'number'); - assert.deepStrictEqual(stdout[0], succeededEvents[0].formatted()); - assert.deepStrictEqual(stdout[1], succeededEvents[1].formatted()); + assert.deepStrictEqual(stdout[0].substring(19), succeededEvents[0].formatted().substring(19)); // chops off timestamp + assert.deepStrictEqual(stdout[1].substring(19), succeededEvents[1].formatted().substring(19)); assert.deepStrictEqual(stderr, []); }); @@ -245,7 +245,7 @@ describe('integration.client.data-api-client', () => { assert.strictEqual(failedEvent.error.errorDescriptors[0].errorCode, 'DOCUMENT_ALREADY_EXISTS'); assert.deepStrictEqual(stdout, []); - assert.deepStrictEqual(stderr[0], failedEvent.formatted()); + assert.deepStrictEqual(stderr[0].substring(19), failedEvent.formatted().substring(19)); // chops off timestamp }); it('should allow monitoring of timed-out commands when enabled', async () => { @@ -297,8 +297,8 @@ describe('integration.client.data-api-client', () => { assert.deepStrictEqual(failedEvent.error.timeout, { generalMethodTimeoutMs: 1, requestTimeoutMs: 1 }); assert.deepStrictEqual(stdout, []); - assert.deepStrictEqual(stderr[0], startedEvent.formatted()); - assert.deepStrictEqual(stderr[1], failedEvent.formatted()); + assert.deepStrictEqual(stderr[0].substring(19), startedEvent.formatted().substring(19)); // chops off timestamp + assert.deepStrictEqual(stderr[1].substring(19), failedEvent.formatted().substring(19)); }); }); }); diff --git a/tests/integration/documents/tables/find-one.test.ts b/tests/integration/documents/tables/find-one.test.ts index 47c153e8..184aefd6 100644 --- a/tests/integration/documents/tables/find-one.test.ts +++ b/tests/integration/documents/tables/find-one.test.ts @@ -14,11 +14,11 @@ // noinspection DuplicatedCode import { - CqlBlob, - CqlDate, - CqlDuration, - CqlTime, - CqlTimestamp, + DataAPIBlob, + DataAPIDate, + DataAPIDuration, + DataAPITime, + DataAPITimestamp, DataAPIVector, InetAddress, UUID, @@ -78,19 +78,19 @@ parallel('integration.documents.tables.find-one', { truncate: 'colls:before', dr int: 0, map: new Map([]), ascii: 'highway_star', - blob: new CqlBlob(Buffer.from('smoke_on_the_water')), + blob: new DataAPIBlob(Buffer.from('smoke_on_the_water')), bigint: 1231233, - date: new CqlDate(), + date: new DataAPIDate(), decimal: BigNumber('12.34567890123456789012345678901234567890'), double: 123.456, - duration: new CqlDuration('P1D'), + duration: new DataAPIDuration('P1D'), float: 123.456, inet: new InetAddress('0:0:0:0:0:0:0:1'), list: [uuid, uuid], set: new Set([uuid, uuid, uuid]), smallint: 123, - time: new CqlTime(), - timestamp: new CqlTimestamp(), + time: new DataAPITime(), + timestamp: new DataAPITimestamp(), tinyint: 123, uuid: UUID.v4(), varint: 12312312312312312312312312312312n, diff --git a/tests/integration/documents/tables/insert-one.test.ts b/tests/integration/documents/tables/insert-one.test.ts index abe32c0f..7a84cd07 100644 --- a/tests/integration/documents/tables/insert-one.test.ts +++ b/tests/integration/documents/tables/insert-one.test.ts @@ -14,11 +14,11 @@ // noinspection DuplicatedCode import { - CqlBlob, - CqlDate, - CqlDuration, - CqlTime, - CqlTimestamp, DataAPIHttpError, DataAPIResponseError, + DataAPIBlob, + DataAPIDate, + DataAPIDuration, + DataAPITime, + DataAPITimestamp, DataAPIHttpError, DataAPIResponseError, DataAPIVector, InetAddress, UUID, @@ -46,19 +46,19 @@ parallel('integration.documents.tables.insert-one', { truncate: 'colls:before' } int: 0, map: new Map([[key, UUID.v4()]]), ascii: 'highway_star', - blob: new CqlBlob(Buffer.from('smoke_on_the_water')), + blob: new DataAPIBlob(Buffer.from('smoke_on_the_water')), bigint: 1231233, - date: new CqlDate(), + date: new DataAPIDate(), decimal: BigNumber('12.34567890123456789012345678901234567890'), double: 123.456, - duration: new CqlDuration('1d'), + duration: new DataAPIDuration('1d'), float: 123.456, inet: new InetAddress('::1'), list: [UUID.v4(), UUID.v7()], set: new Set([UUID.v4(), UUID.v7(), UUID.v7()]), smallint: 123, - time: new CqlTime(), - timestamp: new CqlTimestamp(), + time: new DataAPITime(), + timestamp: new DataAPITimestamp(), tinyint: 123, uuid: UUID.v4(), varint: 12312312312312312312312312312312n, @@ -217,7 +217,7 @@ parallel('integration.documents.tables.insert-one', { truncate: 'colls:before' } ); assert.deepStrictEqual( - (await table.insertOne({ blob: new CqlBlob(buffer) })).insertedId.blob.asBase64(), + (await table.insertOne({ blob: new DataAPIBlob(buffer) })).insertedId.blob.asBase64(), base64, ); @@ -246,14 +246,14 @@ parallel('integration.documents.tables.insert-one', { truncate: 'colls:before' } it('should handle different date insertion cases', async () => { const table = await db.createTable('temp_date', { definition: { columns: { date: 'date' }, primaryKey: 'date' } }); - await assert.rejects(() => table.insertOne({ date: new CqlDate('2000-00-06') }), DataAPIResponseError); - await assert.rejects(() => table.insertOne({ date: new CqlDate('2000-01-00') }), DataAPIResponseError); - await assert.rejects(() => table.insertOne({ date: new CqlDate('2000/01/01') }), DataAPIResponseError); - await assert.rejects(() => table.insertOne({ date: new CqlDate('2000-01-32') }), DataAPIResponseError); - await assert.rejects(() => table.insertOne({ date: new CqlDate('2000-02-30') }), DataAPIResponseError); - await assert.rejects(() => table.insertOne({ date: new CqlDate('+2000-00-06') }), DataAPIResponseError); - await assert.rejects(() => table.insertOne({ date: new CqlDate('-0000-00-06') }), DataAPIResponseError); - await assert.rejects(() => table.insertOne({ date: new CqlDate('10000-00-06') }), DataAPIResponseError); + await assert.rejects(() => table.insertOne({ date: new DataAPIDate('2000-00-06') }), DataAPIResponseError); + await assert.rejects(() => table.insertOne({ date: new DataAPIDate('2000-01-00') }), DataAPIResponseError); + await assert.rejects(() => table.insertOne({ date: new DataAPIDate('2000/01/01') }), DataAPIResponseError); + await assert.rejects(() => table.insertOne({ date: new DataAPIDate('2000-01-32') }), DataAPIResponseError); + await assert.rejects(() => table.insertOne({ date: new DataAPIDate('2000-02-30') }), DataAPIResponseError); + await assert.rejects(() => table.insertOne({ date: new DataAPIDate('+2000-00-06') }), DataAPIResponseError); + await assert.rejects(() => table.insertOne({ date: new DataAPIDate('-0000-00-06') }), DataAPIResponseError); + await assert.rejects(() => table.insertOne({ date: new DataAPIDate('10000-00-06') }), DataAPIResponseError); assert.deepStrictEqual( (await table.insertOne({ date: '1970-01-01' as any })).insertedId.date.toString(), @@ -261,22 +261,22 @@ parallel('integration.documents.tables.insert-one', { truncate: 'colls:before' } ); assert.deepStrictEqual( - (await table.insertOne({ date: new CqlDate('-0001-01-01') })).insertedId.date.toString(), + (await table.insertOne({ date: new DataAPIDate('-0001-01-01') })).insertedId.date.toString(), '-0001-01-01', ); assert.deepStrictEqual( - (await table.insertOne({ date: new CqlDate('9999-12-31') })).insertedId.date.toString(), + (await table.insertOne({ date: new DataAPIDate('9999-12-31') })).insertedId.date.toString(), '9999-12-31', ); assert.deepStrictEqual( - (await table.insertOne({ date: new CqlDate('+10000-12-31') })).insertedId.date.toString(), + (await table.insertOne({ date: new DataAPIDate('+10000-12-31') })).insertedId.date.toString(), '+10000-12-31', ); assert.deepStrictEqual( - (await table.insertOne({ date: new CqlDate('-10000-12-31') })).insertedId.date.toString(), + (await table.insertOne({ date: new DataAPIDate('-10000-12-31') })).insertedId.date.toString(), '-10000-12-31', ); diff --git a/tests/integration/documents/tables/update-one.test.ts b/tests/integration/documents/tables/update-one.test.ts index 4aeb3065..30e5bf4f 100644 --- a/tests/integration/documents/tables/update-one.test.ts +++ b/tests/integration/documents/tables/update-one.test.ts @@ -14,9 +14,9 @@ // noinspection DuplicatedCode import { - CqlBlob, - CqlDate, - CqlDuration, CqlTime, CqlTimestamp, + DataAPIBlob, + DataAPIDate, + DataAPIDuration, DataAPITime, DataAPITimestamp, DataAPIHttpError, DataAPIResponseError, DataAPIVector, InetAddress, @@ -58,19 +58,19 @@ parallel('integration.documents.tables.update-one', { truncate: 'colls:before' } const doc = { map: new Map([]), ascii: 'highway_star', - blob: new CqlBlob(Buffer.from('smoke_on_the_water')), + blob: new DataAPIBlob(Buffer.from('smoke_on_the_water')), bigint: 1231233, - date: new CqlDate(), + date: new DataAPIDate(), decimal: BigNumber('12.34567890123456789012345678901234567890'), double: 123.456, - duration: new CqlDuration('P1D'), + duration: new DataAPIDuration('P1D'), float: 123.456, inet: new InetAddress('0:0:0:0:0:0:0:1'), list: [uuid, uuid], set: new Set([uuid, uuid, uuid]), smallint: 123, - time: new CqlTime(), - timestamp: new CqlTimestamp(), + time: new DataAPITime(), + timestamp: new DataAPITimestamp(), tinyint: 123, uuid: UUID.v4(), varint: 12312312312312312312312312312312n, diff --git a/tests/prelude.test.ts b/tests/prelude.test.ts index be833121..f4cb1efe 100644 --- a/tests/prelude.test.ts +++ b/tests/prelude.test.ts @@ -81,7 +81,7 @@ before(async () => { }); if (keyspace === DEFAULT_KEYSPACE) { - await table.createVectorIndex(`vector_idx_${keyspace}`, 'vector', { metric: 'dot_product' }); + await table.createVectorIndex(`vector_idx_${keyspace}`, 'vector', { options: { metric: 'dot_product' } }); } await table.createIndex(`bigint_idx_${keyspace}`, 'bigint'); }) diff --git a/tests/testlib/fixtures.ts b/tests/testlib/fixtures.ts index f6bda32a..0909470b 100644 --- a/tests/testlib/fixtures.ts +++ b/tests/testlib/fixtures.ts @@ -29,7 +29,7 @@ import { TEST_APPLICATION_URI, TEST_HTTP_CLIENT, } from '@/tests/testlib/config'; -import { DataAPIClientEvent, DataAPIClientEvents, DataAPILoggingConfig } from '@/src/lib'; +import { DataAPIClientEvent, DataAPIClientEventMap, DataAPILoggingConfig } from '@/src/lib'; import { CreateTableDefinition, InferTableSchema } from '@/src/db'; import * as util from 'node:util'; @@ -124,7 +124,7 @@ export const initTestObjects = (opts?: TestObjectsOptions) => { logging, }); - for (const event of ['commandSucceeded', 'adminCommandSucceeded', 'commandFailed', 'adminCommandFailed'] as (keyof DataAPIClientEvents)[]) { + for (const event of ['commandSucceeded', 'adminCommandSucceeded', 'commandFailed', 'adminCommandFailed'] as (keyof DataAPIClientEventMap)[]) { client.on(event, (e: DataAPIClientEvent) => LOGGING_PRED(e, isGlobal) && console.log((isGlobal ? '[Global] ' : '') + util.inspect(e, { depth: null, colors: true }))); } diff --git a/tests/typing/collections/find/cursor.ts b/tests/typing/collections/find/cursor.ts index bf83db2d..fd8ad8d6 100644 --- a/tests/typing/collections/find/cursor.ts +++ b/tests/typing/collections/find/cursor.ts @@ -16,7 +16,7 @@ import { dummyCollection, TestSchema } from '@/tests/typing/collections/prelude'; import { Equal, Expect } from '@/tests/typing/prelude'; -import { IdOf, SomeDoc, StrictFilter, WithId } from '@/src/documents/collections/types'; +import { IdOf, SomeDoc, StrictCollectionFilter, WithId } from '@/src/documents/collections/types'; import { FindCursor } from '@/src/documents'; import { DeepPartial } from '@/src/lib'; @@ -48,10 +48,10 @@ type GetTRawOfCursor = Cursor extends FindCursor ? TRaw type docs_type_is_expected = Expect[], typeof docs>>; }); - cursor.filter({ amount: { $gt: 5 } } satisfies StrictFilter>); + cursor.filter({ amount: { $gt: 5 } } satisfies StrictCollectionFilter>); // @ts-expect-error - am0unt is not a valid field - cursor.filter({ am0unt: { $gt: 5 } } satisfies StrictFilter>); + cursor.filter({ am0unt: { $gt: 5 } } satisfies StrictCollectionFilter>); } { @@ -72,10 +72,10 @@ type GetTRawOfCursor = Cursor extends FindCursor ? TRaw type mappedDoc_type_is_expected = Expect>; }); - mapped.filter({ amount: { $gt: 5 } } satisfies StrictFilter>); + mapped.filter({ amount: { $gt: 5 } } satisfies StrictCollectionFilter>); // @ts-expect-error - am0unt is not a valid field - mapped.filter({ am0unt: { $gt: 5 } } satisfies StrictFilter>); + mapped.filter({ am0unt: { $gt: 5 } } satisfies StrictCollectionFilter>); } { @@ -103,5 +103,5 @@ type GetTRawOfCursor = Cursor extends FindCursor ? TRaw type doc_type_is_expected = Expect>; }); - cursor.filter({ amount: { $gt: 5 } } satisfies StrictFilter>); + cursor.filter({ amount: { $gt: 5 } } satisfies StrictCollectionFilter>); } diff --git a/tests/typing/collections/find/find-one-and-update.ts b/tests/typing/collections/find/find-one-and-update.ts index d7b6796f..a749c634 100644 --- a/tests/typing/collections/find/find-one-and-update.ts +++ b/tests/typing/collections/find/find-one-and-update.ts @@ -14,7 +14,7 @@ // noinspection ExceptionCaughtLocallyJS import { dummyCollection, TestSchema } from '@/tests/typing/collections/prelude'; -import { StrictUpdateFilter } from '@/src/documents/collections/types'; +import { StrictCollectionUpdateFilter } from '@/src/documents/collections/types'; void dummyCollection().findOneAndUpdate({ $vector: [0.25, 0.045, 0.38, 0.31, 0.67], @@ -29,7 +29,7 @@ void dummyCollection().findOneAndUpdate({ $vector: [0.25, 0.045, 0.38, 0.31, 0.67], }, { $set: { 'status': 'active' }, -} satisfies StrictUpdateFilter, { +} satisfies StrictCollectionUpdateFilter, { returnDocument: 'after', }); @@ -41,7 +41,7 @@ void dummyCollection().findOneAndUpdate({ // @ts-expect-error - 'status.car' is not a valid field 'status.car': '', }, -} satisfies StrictUpdateFilter, { +} satisfies StrictCollectionUpdateFilter, { returnDocument: 'after', }); @@ -66,7 +66,7 @@ void dummyCollection().findOneAndUpdate({ items: Symbol('123'), 'customer.phone': '123-456-7890', }, -} satisfies StrictUpdateFilter, { +} satisfies StrictCollectionUpdateFilter, { returnDocument: 'after', upsert: true, }); @@ -89,6 +89,6 @@ void dummyCollection().findOneAndUpdate({ $unset: { amount: '', }, -} satisfies StrictUpdateFilter, { +} satisfies StrictCollectionUpdateFilter, { returnDocument: 'after', }); diff --git a/tests/typing/collections/find/find-one.ts b/tests/typing/collections/find/find-one.ts index f7420d48..52b8f210 100644 --- a/tests/typing/collections/find/find-one.ts +++ b/tests/typing/collections/find/find-one.ts @@ -16,7 +16,7 @@ import { dummyCollection, DynamicSchema, TestSchema } from '@/tests/typing/collections/prelude'; import { Equal, Expect } from '@/tests/typing/prelude'; -import { StrictFilter } from '@/src/documents/collections/types/filter'; +import { StrictCollectionFilter } from '@/src/documents/collections/types/filter'; import { StrictProjection } from '@/src/documents'; void dummyCollection().findOne({}, {}).then((a) => { @@ -66,7 +66,7 @@ void dummyCollection().findOne({ 'purchase_date': { $gte: new Date(123) }, 'items': { $gte: new Date(123) }, 'arr.0': { age: 3 }, -} satisfies StrictFilter, { +} satisfies StrictCollectionFilter, { sort: { 'customer.address.address_line': 1, }, @@ -83,12 +83,12 @@ void dummyCollection().findOne({ $date: 700, }, 'customer.name': { - $eq: 18, + $eq: '18', }, 'customer.age': { $in: [ 102, - '1', + 1, ], }, 'arr.0': ['123'], @@ -112,7 +112,7 @@ void dummyCollection().findOne({ }, // @ts-expect-error - Type mismatch 'arr.0': ['123'], -} satisfies StrictFilter); +} satisfies StrictCollectionFilter); void dummyCollection().findOne({}, { sort: { diff --git a/tests/typing/filter.ts b/tests/typing/filter.ts index a11f2a16..0edc23cd 100644 --- a/tests/typing/filter.ts +++ b/tests/typing/filter.ts @@ -14,11 +14,11 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import type { Filter } from '@/src/documents/collections/types'; +import type { CollectionFilter } from '@/src/documents/collections/types'; import type { ConvolutedSchema2, Schema } from '@/tests/typing/prelude'; import { SomeDoc } from '@/src/documents/collections'; -const test2: Filter = { +const test2: CollectionFilter = { num1: 1, num2: { $in: [1, 2, 3] }, 'obj.obj.num': 3, @@ -35,7 +35,7 @@ const test2: Filter = { ], }; -const test3: Filter = { +const test3: CollectionFilter = { // @ts-expect-error - Invalid type num1: '1', num2: { @@ -46,7 +46,7 @@ const test3: Filter = { '3', ], }, - // Doesn't check nested types + // @ts-expect-error - Invalid type 'obj.obj.num': '3', $and: [ { @@ -77,7 +77,6 @@ const test3: Filter = { }, }, { num1: { - // @ts-expect-error - Invalid op $size: 3, }, }, @@ -86,7 +85,7 @@ const test3: Filter = { ], }; -const test4: Filter = { +const test4: CollectionFilter = { num1: '1', num2: { $in: [1, 2, '3'] }, 'obj.obj.num': '3', @@ -102,12 +101,12 @@ const test4: Filter = { ], }; -const test5: Filter = { +const test5: CollectionFilter = { // Doesn't check nested paths 'obj.obj.xyz': null!, }; -const test6: Filter = { +const test6: CollectionFilter = { $or: [ { numOrArray: { $in: [['1'], 2] } }, { numOrArray: { $gte: 3 } }, @@ -115,7 +114,7 @@ const test6: Filter = { ], }; -const test7: Filter = { +const test7: CollectionFilter = { $and: [ { $or: [] }, { $not: { $and: [ { 'some_random_key': Symbol.for('123') } ] } }, @@ -123,7 +122,7 @@ const test7: Filter = { '123123123': 123123, }; -const test8: Filter = { +const test8: CollectionFilter = { // @ts-expect-error - Invalid type $and: 3, }; diff --git a/tests/typing/strict-filter.ts b/tests/typing/strict-filter.ts index aaf5b9c5..56e64ce4 100644 --- a/tests/typing/strict-filter.ts +++ b/tests/typing/strict-filter.ts @@ -14,10 +14,11 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import type { SomeDoc, SomeId, StrictFilter } from '@/src/documents'; +import type { SomeDoc, SomeId, StrictCollectionFilter } from '@/src/documents'; import type { ConvolutedSchema2, Equal, Expect, Schema, SuperBasicSchema } from '@/tests/typing/prelude'; +import BigNumber from 'bignumber.js'; -type test1 = Expect, { +type test1 = Expect, { num?: number | { $eq?: number, $ne?: number, @@ -25,10 +26,10 @@ type test1 = Expect, { $nin?: number[], $exists?: boolean, } & { - $lt?: number | bigint, - $lte?: number | bigint, - $gt?: number | bigint, - $gte?: number | bigint, + $lt?: number | bigint | BigNumber, + $lte?: number | bigint | BigNumber, + $gt?: number | bigint | BigNumber, + $gte?: number | bigint | BigNumber, }, obj?: { str: string } | { $eq?: { str: string }, @@ -52,22 +53,22 @@ type test1 = Expect, { $nin?: SomeId[], $exists?: boolean, } & { - $lt?: number | bigint, - $lte?: number | bigint, - $gt?: number | bigint, - $gte?: number | bigint, + $lt?: number | bigint | BigNumber, + $lte?: number | bigint | BigNumber, + $gt?: number | bigint | BigNumber, + $gte?: number | bigint | BigNumber, } & ({ $lt?: Date, $lte?: Date, $gt?: Date, $gte?: Date, } | Date) - $and?: StrictFilter[], - $or?: StrictFilter[], - $not?: StrictFilter, + $and?: StrictCollectionFilter[], + $or?: StrictCollectionFilter[], + $not?: StrictCollectionFilter, }>>; -const test2: StrictFilter = { +const test2: StrictCollectionFilter = { num1: 1, num2: { $in: [1, 2, 3] }, 'obj.obj.num': 3, @@ -84,7 +85,7 @@ const test2: StrictFilter = { ], }; -const test3: StrictFilter = { +const test3: StrictCollectionFilter = { // @ts-expect-error - Invalid type num1: '1', num2: { @@ -130,7 +131,7 @@ const test3: StrictFilter = { ], }; -const test4: StrictFilter = { +const test4: StrictCollectionFilter = { num1: '1', num2: { $in: [1, 2, '3'] }, 'obj.obj.num': '3', @@ -146,12 +147,12 @@ const test4: StrictFilter = { ], }; -const test5: StrictFilter = { +const test5: StrictCollectionFilter = { // @ts-expect-error - Invalid path 'obj.obj.xyz': null!, }; -const test6: StrictFilter = { +const test6: StrictCollectionFilter = { $or: [ { numOrArray: { $in: [['1'], 2] } }, { numOrArray: { $gte: 3 } }, @@ -159,7 +160,7 @@ const test6: StrictFilter = { ], }; -const test7: StrictFilter = { +const test7: StrictCollectionFilter = { $and: [ { $or: [] }, { $not: { $and: [{ 'some_random_key': Symbol.for('123') }] } }, @@ -167,7 +168,7 @@ const test7: StrictFilter = { '123123123': 123123, }; -const test8: StrictFilter = { +const test8: StrictCollectionFilter = { // @ts-expect-error - Invalid type $and: 3, }; diff --git a/tests/typing/strict-update-filter.ts b/tests/typing/strict-update-filter.ts index 4c16d581..c7e6f7f3 100644 --- a/tests/typing/strict-update-filter.ts +++ b/tests/typing/strict-update-filter.ts @@ -14,11 +14,11 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { CurrentDate, SomeDoc, ToDotNotation } from '@/src/documents/collections'; -import type { StrictUpdateFilter } from '@/src/documents/collections/types'; +import { CollectionCurrentDate, SomeDoc, ToDotNotation } from '@/src/documents/collections'; +import type { StrictCollectionUpdateFilter } from '@/src/documents/collections/types'; import type { BasicSchema, ConvolutedSchema1, ConvolutedSchema2, Equal, Expect, Schema } from '@/tests/typing/prelude'; -type test1 = Expect, { +type test1 = Expect, { $set?: { num?: number, str?: string, @@ -64,7 +64,7 @@ type test1 = Expect, { 'obj.str': string, obj: string, }>, - $currentDate?: CurrentDate>, + $currentDate?: CollectionCurrentDate>, $min?: Partial<{ num: number | bigint, [k: `any.${string}`]: number | bigint, @@ -92,7 +92,7 @@ type test1 = Expect, { }>, }>> -const test2: StrictUpdateFilter = { +const test2: StrictCollectionUpdateFilter = { $set: { num: 1, str: '1', @@ -162,7 +162,7 @@ const test2: StrictUpdateFilter = { }, }; -const test3: StrictUpdateFilter = { +const test3: StrictCollectionUpdateFilter = { $set: { // @ts-expect-error - Invalid type num1: 'a', @@ -216,7 +216,7 @@ const test3: StrictUpdateFilter = { }, }; -const test4: StrictUpdateFilter = { +const test4: StrictCollectionUpdateFilter = { $set: { num1: 'a', arr: [ @@ -264,7 +264,7 @@ const test4: StrictUpdateFilter = { }, }; -const test5: StrictUpdateFilter = { +const test5: StrictCollectionUpdateFilter = { $set: { // @ts-expect-error - Invalid path 'obj.obj.xyz': '', @@ -295,7 +295,7 @@ const test5: StrictUpdateFilter = { }, }; -const test6: StrictUpdateFilter = { +const test6: StrictCollectionUpdateFilter = { $set: { 'obj.obj.xyz': '', }, @@ -319,7 +319,7 @@ const test6: StrictUpdateFilter = { }, }; -const test7: StrictUpdateFilter = { +const test7: StrictCollectionUpdateFilter = { $set: { numOrBigInt: 1, numOrString: 1, @@ -342,7 +342,7 @@ const test7: StrictUpdateFilter = { }, }; -const test8: StrictUpdateFilter = { +const test8: StrictCollectionUpdateFilter = { $set: { numOrBigInt: 1, numOrString: 1, @@ -365,7 +365,7 @@ const test8: StrictUpdateFilter = { }, }; -const test9: StrictUpdateFilter = { +const test9: StrictCollectionUpdateFilter = { $set: { // @ts-expect-error - Invalid type numOrBigInt: '', @@ -386,7 +386,7 @@ const test9: StrictUpdateFilter = { }, }; -const test10: StrictUpdateFilter = { +const test10: StrictCollectionUpdateFilter = { $set: { numOrBigInt: '', numOrString: 1n, @@ -404,7 +404,7 @@ const test10: StrictUpdateFilter = { }, }; -const test11: StrictUpdateFilter = { +const test11: StrictCollectionUpdateFilter = { $set: { numOrArray: 1, }, @@ -431,7 +431,7 @@ const test11: StrictUpdateFilter = { }, }; -const test12: StrictUpdateFilter = { +const test12: StrictCollectionUpdateFilter = { $set: { numOrArray: [ // @ts-expect-error - Invalid type @@ -456,7 +456,7 @@ const test12: StrictUpdateFilter = { }, }; -const test13: StrictUpdateFilter = { +const test13: StrictCollectionUpdateFilter = { $set: { numOrArray: [1], }, diff --git a/tests/typing/update-filter.ts b/tests/typing/update-filter.ts index 33c5ca50..dfecc79e 100644 --- a/tests/typing/update-filter.ts +++ b/tests/typing/update-filter.ts @@ -15,10 +15,10 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import type { SomeDoc } from '@/src/documents/collections'; -import type { UpdateFilter } from '@/src/documents/collections/types'; +import type { CollectionUpdateFilter } from '@/src/documents/collections/types'; import type { BasicSchema, ConvolutedSchema1, ConvolutedSchema2, Schema } from '@/tests/typing/prelude'; -const test2: UpdateFilter = { +const test2: CollectionUpdateFilter = { $set: { num: 1, str: '1', @@ -88,7 +88,7 @@ const test2: UpdateFilter = { }, }; -const test3: UpdateFilter = { +const test3: CollectionUpdateFilter = { $set: { // @ts-expect-error - Invalid type num1: 'a', @@ -142,7 +142,7 @@ const test3: UpdateFilter = { }, }; -const test4: UpdateFilter = { +const test4: CollectionUpdateFilter = { $set: { num1: 'a', arr: [ @@ -190,7 +190,7 @@ const test4: UpdateFilter = { }, }; -const test5: UpdateFilter = { +const test5: CollectionUpdateFilter = { $set: { 'obj.obj.xyz': '', }, @@ -216,7 +216,7 @@ const test5: UpdateFilter = { }, }; -const test6: UpdateFilter = { +const test6: CollectionUpdateFilter = { $set: { 'obj.obj.xyz': '', }, @@ -240,7 +240,7 @@ const test6: UpdateFilter = { }, }; -const test7: UpdateFilter = { +const test7: CollectionUpdateFilter = { $set: { numOrBigInt: 1, numOrString: 1, @@ -263,7 +263,7 @@ const test7: UpdateFilter = { }, }; -const test8: UpdateFilter = { +const test8: CollectionUpdateFilter = { $set: { numOrBigInt: 1, numOrString: 1, @@ -286,7 +286,7 @@ const test8: UpdateFilter = { }, }; -const test9: UpdateFilter = { +const test9: CollectionUpdateFilter = { $set: { // @ts-expect-error - Invalid type numOrBigInt: '', @@ -306,7 +306,7 @@ const test9: UpdateFilter = { }, }; -const test10: UpdateFilter = { +const test10: CollectionUpdateFilter = { $set: { numOrBigInt: '', numOrString: 1n, @@ -324,7 +324,7 @@ const test10: UpdateFilter = { }, }; -const test11: UpdateFilter = { +const test11: CollectionUpdateFilter = { $set: { numOrArray: 1, }, @@ -351,7 +351,7 @@ const test11: UpdateFilter = { }, }; -const test12: UpdateFilter = { +const test12: CollectionUpdateFilter = { $set: { numOrArray: [ // @ts-expect-error - Invalid type @@ -376,7 +376,7 @@ const test12: UpdateFilter = { }, }; -const test13: UpdateFilter = { +const test13: CollectionUpdateFilter = { $set: { numOrArray: [1], }, diff --git a/tests/unit/db/db.test.ts b/tests/unit/db/db.test.ts index da6dcc94..0839f5dd 100644 --- a/tests/unit/db/db.test.ts +++ b/tests/unit/db/db.test.ts @@ -193,19 +193,19 @@ describe('unit.db', () => { }); }); - it('cshould throw on mismatching environments', () => { + it('should throw on mismatching environments', () => { assert.throws(() => { const db = new DataAPIClient('dummy_token').db(DEMO_APPLICATION_URI); db.admin({ environment: 'dse' }); - }, { message: 'Invalid environment \'astra\' for operation \'db.admin()\' (environment option is not the same as set in the DataAPIClient); expected environment(s): \'dse\'' }); + }, { message: 'Invalid environment \'dse\' for operation \'db.admin()\' (environment option is not the same as set in the DataAPIClient); expected environment(s): \'astra\'' }); assert.throws(() => { const db = new DataAPIClient('dummy_token', { environment: 'dse' }).db(DEMO_APPLICATION_URI); db.admin(); - }, { message: 'Invalid environment \'dse\' for operation \'db.admin()\' (environment option is not the same as set in the DataAPIClient); expected environment(s): \'astra\'' }); + }, { message: 'Invalid environment \'astra\' for operation \'db.admin()\' (environment option is not the same as set in the DataAPIClient); expected environment(s): \'dse\'' }); assert.throws(() => { const db = new DataAPIClient('dummy_token', { environment: 'dse' }).db(DEMO_APPLICATION_URI); db.admin({ environment: 'hcd' }); - }, { message: 'Invalid environment \'dse\' for operation \'db.admin()\' (environment option is not the same as set in the DataAPIClient); expected environment(s): \'hcd\'' }); + }, { message: 'Invalid environment \'hcd\' for operation \'db.admin()\' (environment option is not the same as set in the DataAPIClient); expected environment(s): \'dse\'' }); }); it('should return the admin if on astra db', () => { diff --git a/tests/unit/lib/logging/logger.test.ts b/tests/unit/lib/logging/logger.test.ts index 7dd19d67..4da8aa9b 100644 --- a/tests/unit/lib/logging/logger.test.ts +++ b/tests/unit/lib/logging/logger.test.ts @@ -16,8 +16,8 @@ import { describe, it } from '@/tests/testlib'; import assert from 'assert'; import { parseLoggingConfig } from '@/src/lib/logging/parser'; import { Logger } from '@/src/lib/logging/logger'; -import { EventLoggingDefaults, LoggingEventsWithoutAll } from '@/src/lib/logging/constants'; -import { DataAPIClientEvents, DataAPILoggingConfig } from '@/src/lib'; +import { DataAPILoggingDefaults, LoggingEventsWithoutAll } from '@/src/lib/logging/constants'; +import { DataAPIClientEventMap, DataAPILoggingConfig } from '@/src/lib'; import { NormalizedLoggingConfig } from '@/src/lib/logging/types'; import { beforeEach } from 'mocha'; import TypedEmitter from 'typed-emitter'; @@ -46,15 +46,15 @@ describe('unit.lib.logging.logger', () => { }); it('should return EventLoggingDefaults if config is just \'all\'', () => { - assert.deepStrictEqual(Logger.advanceConfig([3 as any], 'all'), [3, ...EventLoggingDefaults]); + assert.deepStrictEqual(Logger.advanceConfig([3 as any], 'all'), [3, ...DataAPILoggingDefaults]); }); it('should return EventLoggingDefaults if config is just [\'all\']', () => { - assert.deepStrictEqual(Logger.advanceConfig([3 as any], ['all']), [3, ...EventLoggingDefaults]); + assert.deepStrictEqual(Logger.advanceConfig([3 as any], ['all']), [3, ...DataAPILoggingDefaults]); }); it('should return EventLoggingDefaults alongside overrides if config contains [\'all\']', () => { - assert.deepStrictEqual(Logger.advanceConfig([3 as any], ['all', { events: 'commandSucceeded', emits: [] }]), [3, ...EventLoggingDefaults, { events: ['commandSucceeded'], emits: [] }]); + assert.deepStrictEqual(Logger.advanceConfig([3 as any], ['all', { events: 'commandSucceeded', emits: [] }]), [3, ...DataAPILoggingDefaults, { events: ['commandSucceeded'], emits: [] }]); }); it('should return normalized layer if config contains [\'all\'] w/ explicit emits', () => { @@ -92,7 +92,7 @@ describe('unit.lib.logging.logger', () => { { events: ['commandFailed'], emits: ['event', 'stderr'] }, { events: ['commandFailed', 'commandSucceeded'], emits: [] }, { events: ['commandSucceeded', 'commandFailed'], emits: ['event', 'stderr'] }, - ...EventLoggingDefaults, + ...DataAPILoggingDefaults, { events: ['commandSucceeded'], emits: ['event'] }, ]; assert.deepStrictEqual(Logger.advanceConfig([3 as any], config), expected); @@ -115,7 +115,7 @@ describe('unit.lib.logging.logger', () => { emit(name, thing) { events.push([name, thing]); }, - } as TypedEmitter; + } as TypedEmitter; beforeEach(() => { stdout = []; @@ -135,7 +135,7 @@ describe('unit.lib.logging.logger', () => { }); it('should handle default logging behavior', () => { - const logger = new Logger(EventLoggingDefaults, emitter, console); + const logger = new Logger(DataAPILoggingDefaults, emitter, console); logger.commandStarted?.({ timeoutManager: { initial: () => ({}) }, command: {} } as any); assert.strictEqual(events.at(-1)?.[0], 'commandStarted'); assert.ok(events.at(-1)?.[1] instanceof CommandStartedEvent);