Skip to content

Commit deaf56d

Browse files
authored
Merge pull request #268 from rush-db/feat/importJson-separation-and-export-fixes
createMany & importJson separation plus minor export and import impr…
2 parents a4c2f98 + d3eccc7 commit deaf56d

File tree

28 files changed

+604
-276
lines changed

28 files changed

+604
-276
lines changed

.changeset/real-pianos-wash.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@rushdb/javascript-sdk': minor
3+
'@rushdb/mcp-server': minor
4+
'rushdb-dashboard': minor
5+
'rushdb-core': minor
6+
'rushdb-website': minor
7+
'rushdb-docs': minor
8+
---
9+
10+
createMany & importJson separation plus minor export and import improvements

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
node_modules
22
dist
3+
build
34
*.log
45
*.tgz
56
.env

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ import RushDB from '@rushdb/javascript-sdk';
160160
const db = new RushDB("RUSHDB_API_KEY");
161161

162162
// Push data with automatic relationship creation
163-
await db.records.createMany({
163+
await db.records.importJson({
164164
label: "COMPANY",
165165
payload: {
166166
name: 'Google LLC',

docs/docs/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Get instant guidance through our **[RushDB Docs Chat](https://chatgpt.com/g/g-67
6868
const db = new RushDB("RUSHDB_API_KEY");
6969

7070
// Push data with any structure you need
71-
await db.records.createMany({
71+
await db.records.importJson({
7272
label: "PRODUCT",
7373
data: {
7474
title: "Ergonomic Chair",

docs/docs/typescript-sdk/introduction.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const db = new RushDB("RUSHDB_API_KEY");
5757

5858
// Push any data, and RushDB will automatically flatten it into Records
5959
// and establish relationships between them accordingly.
60-
await db.records.createMany({
60+
await db.records.importJson({
6161
label: "COMPANY",
6262
data: {
6363
name: 'Google LLC',
@@ -164,7 +164,7 @@ const db = new RushDB('RUSHDB_API_KEY', {
164164

165165
## SDK Architecture
166166

167-
The RushDB SDK uses a consistent approach for accessing the RushDB API instance across all SDK components. Classes like `Transaction`, `DBRecordInstance`, `DBRecordsArrayInstance` and `Model` all use the static `RushDB.init()` method to obtain the API instance, ensuring a uniform pattern throughout the SDK.
167+
The RushDB SDK uses a consistent approach for accessing the RushDB API instance across all SDK components. Classes like `Transaction`, `DBRecordInstance`, `DBRecordsArrayInstance` and `Model` all use the static `RushDB.getInstance()` method to obtain the API instance, ensuring a uniform pattern throughout the SDK.
168168

169169
This architecture provides several benefits:
170170

@@ -177,7 +177,7 @@ Example of the implementation pattern:
177177
```typescript
178178
// Internal implementation example
179179
async someMethod(param: string): Promise<ApiResponse> {
180-
const instance = await RushDB.init() // Get the RushDB instance
180+
const instance = RushDB.getInstance() // Get the RushDB instance
181181
return await instance.someApi.someMethod(param) // Use the instance to make API calls
182182
}
183183
```

docs/docs/typescript-sdk/models.md

Lines changed: 6 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -149,23 +149,15 @@ export type UserSearchQuery = SearchQuery<typeof UserModel.schema>;
149149

150150
### Model Implementation Architecture
151151

152-
The `Model` class uses the same architectural pattern as other SDK components like `Transaction` and `DBRecordInstance`. It uses the static `RushDB.init()` method to access the API:
152+
The `Model` class uses the same architectural pattern as other SDK components like `Transaction` and `DBRecordInstance`. It uses the static `RushDB.getInstance()` method to access the API:
153153

154154
```typescript
155155
// Internal implementation pattern (from model.ts)
156156
async someMethod(params) {
157-
const instance = await this.getRushDBInstance()
157+
const instance = RushDB.getInstance()
158158
return await instance.someApi.someMethod(params)
159159
}
160160

161-
// getRushDBInstance method in Model class
162-
public async getRushDBInstance(): Promise<RushDB> {
163-
const instance = RushDB.getInstance()
164-
if (instance) {
165-
return await RushDB.init()
166-
}
167-
throw new Error('No RushDB instance found. Please create a RushDB instance first: new RushDB("RUSHDB_API_KEY")')
168-
}
169161
```
170162

171163
This architecture ensures consistent API access across all SDK components.
@@ -248,8 +240,8 @@ import RushDB from '@rushdb/javascript-sdk';
248240
export const db = new RushDB('RUSHDB_API_KEY');
249241

250242
// You can also export a helper function to access the instance
251-
export const getRushDBInstance = async () => {
252-
return await RushDB.init();
243+
export const getRushDBInstance = () => {
244+
return RushDB.getInstance();
253245
};
254246
```
255247

@@ -351,82 +343,9 @@ await AuthorModel.detach({
351343

352344
## Advanced TypeScript Support
353345

354-
When working with RushDB SDK, achieving perfect TypeScript contracts ensures a seamless development experience. TypeScript's strong typing system allows for precise autocomplete suggestions and error checking, particularly when dealing with complex queries and nested models. This section will guide you on how to enhance TypeScript support by defining comprehensive type definitions for your models.
355-
356-
### Defining Comprehensive TypeScript Types
357-
358-
To fully leverage TypeScript's capabilities, you can define types that include all schemas you've registered with `Model`. This will allow you to perform complex queries with nested model fields, ensuring type safety and better autocompletion.
359-
360-
#### Step 1: Create Models with Model
361-
362-
First, define your models using `Model`:
363-
```typescript
364-
import { Model } from '@rushdb/javascript-sdk'
365-
366-
// Create models
367-
const AuthorModel = new Model('author', {
368-
name: { type: 'string' },
369-
email: { type: 'string', unique: true }
370-
});
371-
372-
const PostModel = new Model('post', {
373-
created: { type: 'datetime', default: () => new Date().toISOString() },
374-
title: { type: 'string' },
375-
content: { type: 'string' },
376-
rating: { type: 'number' }
377-
});
378-
379-
const BlogModel = new Model('blog', {
380-
title: { type: 'string' },
381-
description: { type: 'string' }
382-
});
383-
```
384-
385-
#### Step 2: Create an Exportable Type for All Schemas
386-
387-
Next, create an exportable type that includes all the schemas defined in your application:
388-
```typescript
389-
export type MyModels = {
390-
author: typeof AuthorModel.schema
391-
post: typeof PostModel.schema
392-
blog: typeof BlogModel.schema
393-
}
394-
```
395-
396-
#### Step 3: Extend the Models Interface
397-
398-
Add this type declaration to your project. This ensures that RushDB SDK is aware of your models:
399-
```typescript
400-
// index.d.ts or other d.ts file added to include in tsconfig.json
401-
402-
import { MyModels } from './types';
403-
404-
declare module '@rushdb/javascript-sdk' {
405-
export interface Models extends MyModels {}
406-
}
407-
```
408-
409-
### Example Usage: Complex Queries with Type Safety
410-
411-
By following these steps, you can now write complex queries with confidence, knowing that TypeScript will help you avoid errors and provide accurate autocomplete suggestions. Here's an example demonstrating how you can leverage this setup:
412-
413-
```typescript
414-
const query = await db.records.find({
415-
labels: ['post'],
416-
where: {
417-
author: {
418-
name: { $contains: 'John' }, // Checking if the author's name contains 'John'
419-
post: {
420-
rating: { $gt: 5 } // Posts with rating greater than 5
421-
}
422-
}
423-
}
424-
});
425-
```
426-
427-
In this example, the `db.records.find` method allows you to use nested fields in the `where` condition, thanks to the enhanced TypeScript definitions. This ensures that you can easily and accurately query your data, leveraging the full power of TypeScript.
346+
For a complete, up-to-date guide on configuring declaration merging, path aliases, and schema-aware intellisense (including typed related queries), see the Model reference: [TypeScript: extend SDK types for schema-aware suggestions](./typescript-reference/Model#typescript-extend-sdk-types-for-schema-aware-suggestions).
428347

429-
By defining comprehensive type definitions for your models and extending the `Models` interface, you can significantly enhance your TypeScript support when working with RushDB SDK. This approach ensures type safety, better autocompletion, and a more efficient development experience.
348+
Note on result typing with aggregations/grouping: when you use `aggregate` or `groupBy`, the result shape can differ from your schema. You can augment the instance type as `typeof Model.recordInstance & { data: T }` to describe the returned payload. See the dedicated explanation and examples in the Model reference, and the concepts for [Aggregations](../concepts/search/aggregations) and [Grouping](../concepts/search/group-by).
430349

431350
## Working with Transactions
432351

docs/docs/typescript-sdk/records/create-records.md

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,9 @@ Each property draft object supports the following properties:
165165

166166
## Creating Multiple Records
167167

168-
When you need to create multiple records in a single operation, use the `records.createMany` method.
168+
When you need to create multiple flat records (CSV-like rows) in a single operation, use the `records.createMany` method. For nested or complex JSON, use `records.importJson`.
169169

170-
### Using RushDB's `createMany()` Method
170+
### Using RushDB's `createMany()` Method (flat rows only)
171171

172172
```typescript
173173
const authors = await db.records.createMany({
@@ -206,14 +206,58 @@ console.log(authors);
206206
#### Parameters
207207

208208
- `label`: The [label](../../concepts/labels.md)/type for all records
209-
- `data`: Object (nested too) or an array of objects, each representing a record to create
209+
- `data`: An object or array of objects, each a flat record (no nested objects/arrays)
210210
- `options` (optional): Configuration options for record creation:
211211
- `suggestTypes` (boolean, default: `true`): When true, automatically infers data types for [properties](../../concepts/properties.md)
212212
- `castNumberArraysToVectors` (boolean, default: `false`): When true, converts numeric arrays to vector type
213213
- `convertNumericValuesToNumbers` (boolean, default: `false`): When true, converts string numbers to number type
214214
- `capitalizeLabels` (bool): When true, converts all labels to uppercase
215215
- `relationshipType` (str): Default relationship type between nodes
216216
- `returnResult` (bool, default: `false`): When true, returns imported records in response
217+
- Throws if any record contains nested objects/arrays. Use `records.importJson` for that.
218+
219+
### Using RushDB's `importJson()` Method (nested JSON)
220+
221+
Use `importJson` for nested objects, arrays of nested objects, or hash-map like payloads.
222+
223+
Signature:
224+
225+
```ts
226+
db.records.importJson({ data, label?: string, options?: ImportOptions }, tx?)
227+
```
228+
229+
Behavior:
230+
- If `label` is provided, it's used for the import.
231+
- If `label` is omitted, the input must be an object with a single top-level key whose name becomes the label, e.g. `{ ITEM: [ {...}, {...} ] }`.
232+
- If `label` is omitted and the object has multiple top-level keys (e.g. `{ some: 'key', data: 1, nested: { level: 2 } }`), an error is thrown.
233+
234+
Multiple top-level keys:
235+
- Without `label`: not allowed — importJson requires a single top-level key to infer the label and will throw.
236+
- With `label`: allowed — the provided `label` becomes the root label; the multiple keys are treated as nested structure under that root.
237+
- If you want each top-level key to become its own label root, call `importJson` separately per key or pass single-key objects per call.
238+
239+
Examples:
240+
- OK (label inferred):
241+
```json
242+
{ "ITEM": [ { /*...*/ }, { /*...*/ } ] }
243+
```
244+
- OK (label inferred with object):
245+
```json
246+
{ "ITEM": { /*...*/ } }
247+
```
248+
- OK with explicit label (multiple top-level keys):
249+
```json
250+
{ "ITEM": { /*...*/ }, "PRODUCT": { /*...*/ } }
251+
```
252+
Call as: `db.records.importJson({ label: 'INVENTORY', data: { ITEM: {...}, PRODUCT: {...} } })`
253+
- Will throw without label (multiple top-level keys):
254+
```json
255+
{ "ITEM": { /*...*/ }, "PRODUCT": { /*...*/ } }
256+
```
257+
- Will throw without label (mixed keys):
258+
```json
259+
{ "ITEM": { /*...*/ }, "notNestedProp": "12" }
260+
```
217261
- `transaction` (optional): A [transaction](../../concepts/transactions.mdx) object or string to include the operation within a transaction
218262
219263
#### Returns

0 commit comments

Comments
 (0)