Skip to content

Commit dcbddb8

Browse files
committed
Upddated some typings + updated readme
1 parent 5c03077 commit dcbddb8

File tree

5 files changed

+159
-19
lines changed

5 files changed

+159
-19
lines changed

README.md

Lines changed: 138 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22

33
`astra-db-ts` is a TypeScript client for interacting with [DataStax Astra DB](https://astra.datastax.com/signup).
44

5-
*This README targets v1.0.0+, which introduces a whole new API. Click [here](https://www.youtube.com/watch?v=dQw4w9WgXcQ) for the pre-existing client readme.*
6-
7-
*For the sake of my job, I hope I remember to update that link before release.*
5+
*This README targets v1.0.0+, which introduces a whole new API. Click [here](https://github.com/datastax/astra-db-ts/tree/90ebeac6fec53fd951126c2bcc010c87f7f678f8?tab=readme-ov-file#datastaxastra-db-ts) for the pre-existing client readme.*
86

97
## Quickstart
108

11-
Use your preferred package manager to install `@datastax/astra-db-ts`. Note that this requires a Node-compatable runtime.
9+
Use your preferred package manager to install `@datastax/astra-db-ts`. Note that this is not supported in browsers.
1210

13-
Get the *API endpoint* and your *applicaton token* for your Astra DB instance @ [astra.datastax.com](https://astra.datastax.com).
11+
Get the *API endpoint* and your *application token* for your Astra DB instance @ [astra.datastax.com](https://astra.datastax.com).
1412

1513
Try the following code after setting the following environment variables:
1614

@@ -93,7 +91,7 @@ Next steps:
9391

9492
### Abstraction diagram
9593

96-
astra-db-ts's abstractions for working at the data and admin layers are structured as depicted by this diagram:
94+
`astra-db-ts`'s abstractions for working at the data and admin layers are structured as depicted by this diagram:
9795

9896
![Class hierarchy diagram](assets/imgs/class-hierarchy.png)
9997

@@ -118,17 +116,106 @@ const admin = client.admin();
118116
})();
119117
```
120118

121-
## Working with ObjectIds and UUIDs
119+
### Getting the most out of the typing
120+
121+
`astra-db-ts` is a typescript-first library, performing minimal runtime type-checking. As such, it provides
122+
a rich set of types to help you write type-safe code.
123+
124+
Here are some examples of how you can properly leverage types to make your code more robust:
125+
126+
```typescript
127+
import { DataAPIClient, StrictFilter, StrictSort, UUID } from '@/src/index';
128+
129+
const client = new DataAPIClient('*TOKEN*');
130+
const db = client.db('*ENDPOINT*', { namespace: '*NAMESPACE*' });
131+
132+
// You can strictly type your collections for proper type-checking
133+
interface Person {
134+
_id: UUID,
135+
name: string,
136+
interests: {
137+
favoriteBand?: string,
138+
friend?: UUID,
139+
}
140+
}
141+
142+
(async () => {
143+
// Create your collections with a defaultId type to enforce the type of the _id field
144+
// (Otherwise it'll default to a string UUID that wouldn't be deserialized as a UUID by the client)
145+
const collection = await db.createCollection<Person>('my_collection', { defaultId: { type: 'uuidv7' } });
146+
147+
// Now it'll raise type-errors if you try to insert a document with the wrong shape
148+
await collection.insertOne({
149+
_id: new UUID('e7f1f3a0-7e3d-11eb-9439-0242ac130002'),
150+
name: 'John',
151+
interests: {
152+
favoriteBand: 'Nightwish',
153+
},
154+
// @ts-expect-error - 'eyeColor' does not exist in type MaybeId<Person>
155+
eyeColor: 'blue',
156+
});
157+
158+
// You can use the 'Strict*' version of Sort/Projection/Filter/UpdateFilter for proper type-checking and autocomplete
159+
await collection.findOne({
160+
// @ts-expect-error - Type number is not assignable to type FilterExpr<UUID | undefined>
161+
'interests.friend': 3,
162+
} satisfies StrictFilter<Person>, {
163+
sort: {
164+
name: 1,
165+
// @ts-expect-error - 'interests.favoriteColor' does not exist in type StrictProjection<Person>
166+
'interests.favoriteColor': 1 as const,
167+
} satisfies StrictSort<Person>,
168+
});
169+
})();
170+
```
171+
172+
### Working with Dates
173+
174+
Native JS `Date` objects can be used anywhere in documents to represent dates and times.
175+
176+
Document fields stored using the `{ $date: number }` will also be returned as Date objects when read.
177+
178+
```typescript
179+
import { DataApiClient } from '@datastax/astra-db-ts';
180+
181+
// Reference an untyped collection
182+
const client = new DataApiClient('TOKEN');
183+
const db = client.db('ENDPOINT', { namespace: 'NAMESPACE' });
184+
const collection = db.collection('COLLECTION');
185+
186+
// Insert documents with some dates
187+
await collection.insertOne({ dateOfBirth: new Date(1394104654000) });
188+
await collection.insertOne({ dateOfBirth: new Date('1863-05-28') });
189+
190+
// Update a document with a date and setting lastModified to now
191+
await collection.updateOne(
192+
{
193+
dateOfBirth: new Date('1863-05-28'),
194+
},
195+
{
196+
$set: { message: 'Happy Birthday!' },
197+
$currentDate: { lastModified: true },
198+
},
199+
);
200+
201+
// Will print *around* `new Date()` (i.e. when server processed the request)
202+
const found = await collection.findOne({ dateOfBirth: { $lt: new Date('1900-01-01') } });
203+
console.log(found?.lastModified);
204+
```
205+
206+
### Working with ObjectIds and UUIDs
207+
208+
`astra-db-ts` exports an `ObjectId` and `UUID` class for working with these types in the database.
122209

123-
astra-db-ts exports an `ObjectId` and `UUID` class for working with these types in the database. Here's an example:
210+
Note that these are custom classes, and *not* the ones from the `bson` package. Make sure you're using the right one!
124211

125212
```typescript
126213
import { DataAPIClient, ObjectId, UUID } from '@datastax/astra-db-ts';
127214

128215
interface Person {
129216
_id: ObjectId | UUID,
130217
name: string,
131-
friendId?: string,
218+
friendId?: ObjectId | UUID,
132219
}
133220

134221
// Connect to the db
@@ -152,7 +239,7 @@ const db = client.db('*ENDPOINT*', { namespace: '*NAMESPACE*' });
152239

153240
await collection.updateOne(
154241
{ name: 'Jane' },
155-
{ $set: { friendId: friendId.toString() } },
242+
{ $set: { friendId } },
156243
);
157244

158245
// And let's get Jane as a document
@@ -162,4 +249,44 @@ const db = client.db('*ENDPOINT*', { namespace: '*NAMESPACE*' });
162249
})();
163250
```
164251

165-
Note that these are custom classes, and *not* the ones from the `bson` package. Make sure you're using the right one!
252+
### Monitoring/logging
253+
254+
[Like Mongo](https://www.mongodb.com/docs/drivers/node/current/fundamentals/logging/), `astra-db-ts` doesn't provide a
255+
traditional logging system—instead, it uses a "monitoring" system based on event emitters, which allow you to listen to
256+
events and log them as you see fit.
257+
258+
Supported events include `commandStarted`, `commandSucceeded`, `commandFailed`, and `adminCommandStarted`,
259+
`adminCommandPolling`, `adminCommandSucceeded`, `adminCommandFailed`.
260+
261+
Note that it's disabled by default, and it can be enabled by passing `monitorCommands: true` option to the root options'
262+
`dbOptions` and `adminOptions`.
263+
264+
```typescript
265+
import { DataAPIClient } from '@datastax/astra-db-ts';
266+
267+
const client = new DataAPIClient('*TOKEN*', {
268+
dbOptions: {
269+
monitorCommands: true,
270+
},
271+
});
272+
273+
client.on('commandStarted', (event) => {
274+
console.log(`Running command ${event.commandName}`);
275+
});
276+
277+
client.on('commandSucceeded', (event) => {
278+
console.log(`Command ${event.commandName} succeeded in ${event.duration}ms`);
279+
});
280+
281+
client.on('commandFailed', (event) => {
282+
console.error(`Command ${event.commandName} failed w/ error ${event.error}`);
283+
});
284+
285+
const db = client.db('*ENDPOINT*');
286+
const coll = db.collection('*COLLECTION*');
287+
288+
// Should log
289+
// - "Running command insertOne"
290+
// - "Command insertOne succeeded in <time>ms"
291+
await coll.insertOne({ name: 'Queen' });
292+
```

src/data-api/collection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ export class Collection<Schema extends SomeDoc = SomeDoc> {
930930
*
931931
* @see StrictFilter
932932
*/
933-
public async findOne<GetSim extends boolean = false>(filter: Filter<Schema>, options?: FindOneOptions<GetSim>): Promise<FoundDoc<Schema, GetSim> | null> {
933+
public async findOne<const GetSim extends boolean = false>(filter: Filter<Schema>, options?: FindOneOptions<GetSim>): Promise<FoundDoc<Schema, GetSim> | null> {
934934
options = coalesceVectorSpecialsIntoSort(options);
935935

936936
const command: FindOneCommand = {

src/data-api/types/dot-notation.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import type { SomeDoc } from '@/src/data-api';
15+
import { SomeDoc, UUID, ObjectId } from '@/src/data-api';
1616

1717
/**
1818
* Converts some {@link Schema} into a type representing its dot notation (object paths).
@@ -45,9 +45,9 @@ import type { SomeDoc } from '@/src/data-api';
4545
* }
4646
* ```
4747
*/
48-
export type ToDotNotation<Schema extends SomeDoc> = Merge<_ToDotNotation<Required<Schema>, ''>>;
48+
export type ToDotNotation<Schema extends SomeDoc> = Merge<_ToDotNotation<Schema, ''>>;
4949

50-
type _ToDotNotation<Elem extends SomeDoc, Prefix extends string> = {
50+
type _ToDotNotation<_Elem extends SomeDoc, Prefix extends string, Elem = Required<_Elem>> = {
5151
[Key in keyof Elem]:
5252
SomeDoc extends Elem
5353
? (
@@ -64,6 +64,8 @@ type _ToDotNotation<Elem extends SomeDoc, Prefix extends string> = {
6464
| { [Path in `${Prefix}${Key & string}`]: Elem[Key] }
6565
| { [Path in `${Prefix}${Key & string}.${number}`]: Elem[Key][number] }
6666
) :
67+
Elem[Key] extends UUID | ObjectId
68+
? { [Path in `${Prefix}${Key & string}`]: Elem[Key] } :
6769
Elem[Key] extends Date
6870
? { [Path in `${Prefix}${Key & string}`]: Date | { $date: number } } :
6971
Elem[Key] extends SomeDoc

tests/typing/dot-notation.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414

1515
/* eslint-disable @typescript-eslint/no-unused-vars */
1616

17-
import { BasicSchema, ConvolutedSchema1, Equal, Expect, Schema } from '@/tests/typing/prelude';
17+
import { BasicSchema, ConvolutedSchema1, ConvolutedSchema3, Equal, Expect, Schema } from '@/tests/typing/prelude';
1818
import { ToDotNotation } from '@/src/data-api/types';
19-
import { SomeDoc } from '@/src/data-api';
19+
import { SomeDoc, UUID } from '@/src/data-api';
2020

2121
type test1 = Expect<Equal<ToDotNotation<BasicSchema>, {
2222
num: number,
@@ -35,7 +35,7 @@ type test2 = Expect<Equal<ToDotNotation<Schema>, {
3535
'obj.str2': string,
3636
'obj.obj': { num: number, any: SomeDoc },
3737
'obj.obj.num': number,
38-
'obj.obj.any': SomeDoc,
38+
'obj.obj.any': SomeDoc & Required<SomeDoc>,
3939
[k: `obj.obj.any.${string}`]: any,
4040
arr: string[],
4141
[k: `arr.${number}`]: string,
@@ -104,3 +104,7 @@ const test9: Partial<ToDotNotation<ConvolutedSchema1>> = {
104104
// @ts-expect-error - Invalid type
105105
numOrString: 1n,
106106
}
107+
108+
const test10: Partial<ToDotNotation<ConvolutedSchema3>> = {
109+
'obj.id': UUID.v7(),
110+
}

tests/typing/prelude.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { SomeDoc } from '@/src/data-api';
15+
import { SomeDoc, UUID } from '@/src/data-api';
16+
import { ObjectId } from 'bson';
1617

1718
export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
1819
export type Expect<T extends true> = T;
@@ -55,3 +56,9 @@ export interface ConvolutedSchema1 {
5556
export interface ConvolutedSchema2 {
5657
numOrArray: number | string[],
5758
}
59+
60+
export interface ConvolutedSchema3 {
61+
obj: {
62+
id: UUID | ObjectId,
63+
}
64+
}

0 commit comments

Comments
 (0)