@@ -36,40 +36,41 @@ const db = client.db(process.env.CLIENT_DB_URL!, { token: process.env.CLIENT_DB_
36
36
37
37
// The `VectorDoc` interface adds `$vector?: DataAPIVector` as a field to the collection type
38
38
interface Dream extends VectorDoc {
39
- _id: ObjectId , // Uses an `astra-db-ts` provided type here (NOT the `bson` version)
39
+ _id: ObjectId ,
40
40
summary: string ,
41
- tags? : string [], // No sets/maps available without creating custom ser/des rules
41
+ tags? : string [],
42
42
}
43
43
44
44
(async () => {
45
- // Create the table using our helper function.
46
- // The _id should be an `ObjectId` type, as specified by `defaultId.type`
45
+ // Create the collection with a custom default ID type
47
46
const collection = await db .createCollection <Dream >(' dreams' , {
48
47
defaultId: { type: ' objectId' },
49
48
});
50
49
51
- // Batch-insert some rows into the table
50
+ // Batch-insert some rows into the table.
52
51
// _id can be optionally provided, or be auto-generated @ the server side
53
52
await collection .insertMany ([{
54
53
summary: ' A dinner on the Moon' ,
55
- $vector: vector ([0.2 , - 0.3 , - 0.5 ]), // Shorthand for `new DataAPIVector([0.2, -0.3, -0.5])`
54
+ $vector: vector ([0.2 , - 0.3 , - 0.5 ]),
56
55
}, {
57
56
summary: ' Riding the waves' ,
58
57
$vector: vector ([0 , 0.2 , 1 ]),
59
58
tags: [' sport' ],
60
59
}, {
61
- _id: oid (' 674f0f5c1c162131319fa09e' ), // Shorthand for `new ObjectId('674f0f5c1c162131319fa09e')`
60
+ _id: oid (' 674f0f5c1c162131319fa09e' ),
62
61
summary: ' Meeting Beethoven at the dentist' ,
63
62
$vector: vector ([0.2 , 0.6 , 0 ]),
64
63
}]);
65
64
66
65
// Hm, changed my mind
67
- await collection .updateOne ({ id: 103 }, { $set: { summary: ' Surfers\' paradise' } });
66
+ await collection .updateOne ({ _id: oid (' 674f0f5c1c162131319fa09e' ) }, {
67
+ $set: { summary: ' Surfers\' paradise' }
68
+ });
68
69
69
- // Let's see what we've got
70
+ // Let's see what we've got, by performing a vector search
70
71
const cursor = collection .find ({})
71
- .sort ({ vector: vector ([0 , 0.2 , 0.4 ]) }) // Performing a vector search
72
- .includeSimilarity (true ) // The found doc is inferred to have `$similarity` as a property now
72
+ .sort ({ vector: vector ([0 , 0.2 , 0.4 ]) })
73
+ .includeSimilarity (true )
73
74
.limit (2 );
74
75
75
76
// This would print:
@@ -87,44 +88,42 @@ interface Dream extends VectorDoc {
87
88
### Tables
88
89
89
90
``` typescript
90
- import { DataAPIClient , InferTableSchema , vector } from ' @datastax/astra-db-ts' ;
91
+ import { DataAPIClient , InferTableSchema , Table , vector } from ' @datastax/astra-db-ts' ;
91
92
92
93
// Connect to the db
93
94
const client = new DataAPIClient ({ logging: ' all' });
94
95
const db = client .db (process .env .CLIENT_DB_URL ! , { token: process .env .CLIENT_DB_TOKEN ! });
95
96
96
- // Create a table through the Data API if it does not yet exist.
97
- // Returns the created table through a function so we can use the inferred type of the table ourselves
98
- // (instead of having to manually define it)
99
- const mkDreamsTable = async () => await db .createTable (' dreams' , {
100
- definition: {
101
- columns: {
102
- id: ' int' , // Shorthand notation for { type: 'int' }
103
- summary: ' text' ,
104
- tags: { type: ' set' , valueType: ' text' }, // Collection types require additional type information
105
- vector: { type: ' vector' , dimension: 3 }, // Auto-embedding-generation can be enabled through a `service` block
106
- },
107
- primaryKey: ' id' , // Shorthand for { partitionBy: ['id'] }
97
+ // Define the table's schema so we can infer the type of the table automatically (TS v5.0+)
98
+ const DreamsTableSchema = Table .schema ({
99
+ columns: {
100
+ id: ' int' ,
101
+ summary: ' text' ,
102
+ tags: { type: ' set' , valueType: ' text' },
103
+ vector: { type: ' vector' , dimension: 3 },
108
104
},
109
- ifNotExists: true , // If any table with the same name exists, do nothing
110
- }); // (note that this does not check if the tables are the same)
105
+ primaryKey: ' id ' ,
106
+ });
111
107
112
108
// Infer the TS-equivalent type from the table definition (like zod or arktype). Equivalent to:
113
109
//
114
110
// interface TableSchema {
115
- // id: number, -- A primary key component, so it's required
116
- // summary?: string | null, -- Not a primary key, so it's optional and may return as null when found
117
- // tags?: Set<string>, -- Sets/maps/lists are optional to insert, but will actually be returned as empty collections instead of null
118
- // vector?: DataAPIVector | null, -- Vectors, however, may be null.
111
+ // id: number,
112
+ // summary?: string | null,
113
+ // tags?: Set<string>,
114
+ // vector?: DataAPIVector | null,
119
115
// }
120
- type Dream = InferTableSchema <typeof mkDreamsTable >;
116
+ type Dream = InferTableSchema <typeof DreamsTableSchema >;
121
117
122
118
(async () => {
123
- // Create the table using our helper function.
119
+ // Create the table if it doesn't already exist
124
120
// Table will be typed as `Table<Dream, { id: number }>`, where the former is the schema, and the latter is the primary key
125
- const table = await mkDreamsTable ();
121
+ const table = await db .createTable (' dreams' , {
122
+ definition: DreamsTableSchema ,
123
+ ifNotExists: true ,
124
+ });
126
125
127
- // Enables vector search on the table ( on the 'vector' column)
126
+ // Create a vector index on the vector column so we can perform ANN searches on the table
128
127
await table .createVectorIndex (' dreams_vector_idx' , ' vector' , {
129
128
options: { metric: ' cosine' },
130
129
ifNotExists: true ,
@@ -134,12 +133,12 @@ type Dream = InferTableSchema<typeof mkDreamsTable>;
134
133
const rows: Dream [] = [{
135
134
id: 102 ,
136
135
summary: ' A dinner on the Moon' ,
137
- vector: vector ([0.2 , - 0.3 , - 0.5 ]), // Shorthand for `new DataAPIVector([0.2, -0.3, -0.5])`
136
+ vector: vector ([0.2 , - 0.3 , - 0.5 ]),
138
137
}, {
139
138
id: 103 ,
140
139
summary: ' Riding the waves' ,
141
140
vector: vector ([0 , 0.2 , 1 ]),
142
- tags: new Set ([' sport' ]), // Collection types use native JS collections
141
+ tags: new Set ([' sport' ]),
143
142
}, {
144
143
id: 37 ,
145
144
summary: ' Meeting Beethoven at the dentist' ,
@@ -148,12 +147,14 @@ type Dream = InferTableSchema<typeof mkDreamsTable>;
148
147
await table .insertMany (rows );
149
148
150
149
// Hm, changed my mind
151
- await table .updateOne ({ id: 103 }, { $set: { summary: ' Surfers\' paradise' } });
150
+ await table .updateOne ({ id: 103 }, {
151
+ $set: { summary: ' Surfers\' paradise' }
152
+ });
152
153
153
- // Let's see what we've got
154
+ // Let's see what we've got, by performing a vector search
154
155
const cursor = table .find ({})
155
- .sort ({ vector: vector ([0 , 0.2 , 0.4 ]) }) // Performing a vector search
156
- .includeSimilarity (true ) // The found doc is inferred to have `$similarity` as a property now
156
+ .sort ({ vector: vector ([0 , 0.2 , 0.4 ]) })
157
+ .includeSimilarity (true )
157
158
.limit (2 );
158
159
159
160
// This would print:
@@ -168,6 +169,56 @@ type Dream = InferTableSchema<typeof mkDreamsTable>;
168
169
})();
169
170
```
170
171
172
+ <details >
173
+ <summary ><i >Inferring the table schema pre-TS v5.0</i ></summary >
174
+
175
+ Before TypeScript 5.0, there was no support for "const type parameters" (e.g. ` f<const T>(t: T): T ` ) which ` Table.schema ` relies on.
176
+
177
+ No worries though—if you're using TypeScript 4.x or below, you can still infer the schema automatically, albeit with less language server support.
178
+
179
+ Schema object type errors may be non-local and harder to debug, but the code will still work as expected.
180
+
181
+ ``` ts
182
+ const DreamsTableSchema = <const >{
183
+ columns: {
184
+ id: ' int' ,
185
+ summary: ' text' ,
186
+ tags: { type: ' set' , valueType: ' text' },
187
+ vector: { type: ' vector' , dimension: 3 },
188
+ },
189
+ primaryKey: ' id' ,
190
+ };
191
+
192
+ // Still works, but you need to ensure DreamsTableSchema is a properly typed const object
193
+ type Dream = InferTableSchema <typeof DreamsTableSchema >;
194
+ type DreamPK = InferTablePrimaryKey <typeof DreamsTableSchema >;
195
+
196
+ (async () => {
197
+ // Necessary to explicitly set the type of the table schema and primary key here
198
+ const table = await db .createTable <Dream , DreamPK >(' dreams' , {
199
+ definition: DreamsTableSchema ,
200
+ ifNotExists: true ,
201
+ });
202
+ })();
203
+ ```
204
+
205
+ If you're using TypeScript 4.9, you can at least use the ` satisfies ` operator to localize any definition type errors.
206
+
207
+ ``` ts
208
+ const DreamsTableSchema = <const >{
209
+ columns: {
210
+ id: ' int' ,
211
+ summary: ' text' ,
212
+ tags: { type: ' set' , valueType: ' text' },
213
+ vector: { type: ' vector' , dimension: 3 },
214
+ },
215
+ primaryKey: ' id' ,
216
+ } satisfies CreateTableDefinition ;
217
+
218
+ type Dream = InferTableSchema <typeof DreamsTableSchema >;
219
+ ```
220
+ </details >
221
+
171
222
### Next steps
172
223
173
224
- More info and usage patterns are given in the ts-doc of classes and methods
@@ -250,11 +301,9 @@ const tp = new UsernamePasswordTokenProvider('*USERNAME*', '*PASSWORD*');
250
301
const client = new DataAPIClient (tp , { environment: ' dse' });
251
302
const db = client .db (' *ENDPOINT*' );
252
303
253
- // You'll also need to pass it to db.admin() when not using Astra for typing purposes
254
- // If the environment does not match, an error will be thrown as a reminder
255
- // `environment: 'dse'` makes the return type be `DataAPIDbAdmin`
304
+ // A common idiom may be to use `dbAdmin.createKeyspace` with `updateDbKeyspace` to initialize the keyspace when necessary
256
305
const dbAdmin = db .admin ({ environment: ' dse' });
257
- dbAdmin .createNamespace (' ...' );
306
+ dbAdmin .createKeyspace (' ...' , { updateDbKeyspace: true } );
258
307
```
259
308
260
309
The ` TokenProvider ` class is an extensible concept to allow you to create or even refresh your tokens
@@ -268,9 +317,9 @@ as necessary, depending on the Data API backend. Tokens may even be omitted if n
268
317
269
318
## Non-standard environment support
270
319
271
- ` astra-db-ts ` is designed foremost to work in Node.js environments.
320
+ ` astra-db-ts ` is designed first and foremost to work in Node.js environments.
272
321
273
- It will work in edge runtimes and other non-node environments as well, though it'll use the native ` fetch ` API for HTTP
322
+ However, it will work in edge runtimes and other non-node environments as well, though it may use the native ` fetch ` API for HTTP
274
323
requests, as opposed to ` fetch-h2 ` which provides extended HTTP/2 and HTTP/1.1 support for performance.
275
324
276
325
By default, it'll attempt to use ` fetch-h2 ` if available, and fall back to ` fetch ` if not available in that environment.
@@ -331,12 +380,13 @@ to the native fetch implementation instead if importing fails.
331
380
332
381
### Browser support
333
382
334
- The Data API itself does not natively support browsers, so ` astra-db-ts ` isn't technically supported in browsers either .
383
+ ` astra-db-ts ` is designed to work in server-side environments, but it can technically work in the browser as well .
335
384
336
- However, if, for some reason, you really want to use this in a browser, you can probably do so by installing the
337
- ` events ` polyfill and setting up a [ CORS proxy] ( https://github.com/Rob--W/cors-anywhere ) to forward requests to the Data API.
385
+ However, if, for some reason, you really want to use this in a browser, you may need to install the ` events ` polyfill,
386
+ and possibly set up a CORS proxy (such as [ CORS Anywhere] ( https://github.com/Rob--W/cors-anywhere ) ) to forward requests
387
+ to the Data API.
338
388
339
- But keep in mind that this is not officially supported, and may be very insecure if you're encoding sensitive
340
- data into the browser client .
389
+ But keep in mind that this may be very insecure, especially if you're hardcoding sensitive data into your client-side
390
+ code, as it's trivial for anyone to inspect the code and extract the token (through XSS attacks or otherwise) .
341
391
342
- (See ` examples/browser ` for a full example of this workaround in action.)
392
+ (See ` examples/browser ` for a full example of browser usage in action.)
0 commit comments