@@ -36,40 +36,41 @@ const db = client.db(process.env.CLIENT_DB_URL!, { token: process.env.CLIENT_DB_
3636
3737// The `VectorDoc` interface adds `$vector?: DataAPIVector` as a field to the collection type
3838interface Dream extends VectorDoc {
39- _id: ObjectId , // Uses an `astra-db-ts` provided type here (NOT the `bson` version)
39+ _id: ObjectId ,
4040 summary: string ,
41- tags? : string [], // No sets/maps available without creating custom ser/des rules
41+ tags? : string [],
4242}
4343
4444(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
4746 const collection = await db .createCollection <Dream >(' dreams' , {
4847 defaultId: { type: ' objectId' },
4948 });
5049
51- // Batch-insert some rows into the table
50+ // Batch-insert some rows into the table.
5251 // _id can be optionally provided, or be auto-generated @ the server side
5352 await collection .insertMany ([{
5453 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 ]),
5655 }, {
5756 summary: ' Riding the waves' ,
5857 $vector: vector ([0 , 0.2 , 1 ]),
5958 tags: [' sport' ],
6059 }, {
61- _id: oid (' 674f0f5c1c162131319fa09e' ), // Shorthand for `new ObjectId('674f0f5c1c162131319fa09e')`
60+ _id: oid (' 674f0f5c1c162131319fa09e' ),
6261 summary: ' Meeting Beethoven at the dentist' ,
6362 $vector: vector ([0.2 , 0.6 , 0 ]),
6463 }]);
6564
6665 // 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+ });
6869
69- // Let's see what we've got
70+ // Let's see what we've got, by performing a vector search
7071 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 )
7374 .limit (2 );
7475
7576 // This would print:
@@ -87,44 +88,42 @@ interface Dream extends VectorDoc {
8788### Tables
8889
8990``` typescript
90- import { DataAPIClient , InferTableSchema , vector } from ' @datastax/astra-db-ts' ;
91+ import { DataAPIClient , InferTableSchema , Table , vector } from ' @datastax/astra-db-ts' ;
9192
9293// Connect to the db
9394const client = new DataAPIClient ({ logging: ' all' });
9495const db = client .db (process .env .CLIENT_DB_URL ! , { token: process .env .CLIENT_DB_TOKEN ! });
9596
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 },
108104 },
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+ });
111107
112108// Infer the TS-equivalent type from the table definition (like zod or arktype). Equivalent to:
113109//
114110// 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,
119115// }
120- type Dream = InferTableSchema <typeof mkDreamsTable >;
116+ type Dream = InferTableSchema <typeof DreamsTableSchema >;
121117
122118(async () => {
123- // Create the table using our helper function.
119+ // Create the table if it doesn't already exist
124120 // 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+ });
126125
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
128127 await table .createVectorIndex (' dreams_vector_idx' , ' vector' , {
129128 options: { metric: ' cosine' },
130129 ifNotExists: true ,
@@ -134,12 +133,12 @@ type Dream = InferTableSchema<typeof mkDreamsTable>;
134133 const rows: Dream [] = [{
135134 id: 102 ,
136135 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 ]),
138137 }, {
139138 id: 103 ,
140139 summary: ' Riding the waves' ,
141140 vector: vector ([0 , 0.2 , 1 ]),
142- tags: new Set ([' sport' ]), // Collection types use native JS collections
141+ tags: new Set ([' sport' ]),
143142 }, {
144143 id: 37 ,
145144 summary: ' Meeting Beethoven at the dentist' ,
@@ -148,12 +147,14 @@ type Dream = InferTableSchema<typeof mkDreamsTable>;
148147 await table .insertMany (rows );
149148
150149 // 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+ });
152153
153- // Let's see what we've got
154+ // Let's see what we've got, by performing a vector search
154155 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 )
157158 .limit (2 );
158159
159160 // This would print:
@@ -168,6 +169,56 @@ type Dream = InferTableSchema<typeof mkDreamsTable>;
168169})();
169170```
170171
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+
171222### Next steps
172223
173224- 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*');
250301const client = new DataAPIClient (tp , { environment: ' dse' });
251302const db = client .db (' *ENDPOINT*' );
252303
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
256305const dbAdmin = db .admin ({ environment: ' dse' });
257- dbAdmin .createNamespace (' ...' );
306+ dbAdmin .createKeyspace (' ...' , { updateDbKeyspace: true } );
258307```
259308
260309The ` 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
268317
269318## Non-standard environment support
270319
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.
272321
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
274323requests, as opposed to ` fetch-h2 ` which provides extended HTTP/2 and HTTP/1.1 support for performance.
275324
276325By 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.
331380
332381### Browser support
333382
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 .
335384
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.
338388
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) .
341391
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