CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-objection

An SQL-friendly ORM for Node.js built on Knex.js with powerful query building, relationship handling, and JSON Schema validation

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

graph-operations.mddocs/

Graph Operations

Insert, update, and upsert operations for complex nested data structures with relationship handling.

Capabilities

Insert Graph

Insert a model graph with nested relations in a single operation.

/**
 * Insert a graph of models with their relations
 * @param graph - Object or array of objects representing the model graph
 * @param options - Insert graph options
 * @returns QueryBuilder instance
 */
insertGraph(graph: object | object[], options?: InsertGraphOptions): QueryBuilder;

/**
 * Insert graph and return the inserted models
 * @param graph - Object or array representing the model graph
 * @param options - Insert graph options
 * @returns QueryBuilder instance
 */
insertGraphAndFetch(graph: object | object[], options?: InsertGraphOptions): QueryBuilder;

interface InsertGraphOptions {
  relate?: boolean | string[];
  allowRefs?: boolean;
}

Usage Examples:

// Insert person with pets
const graph = {
  firstName: 'John',
  lastName: 'Doe',
  pets: [
    { name: 'Fluffy', species: 'cat' },
    { name: 'Buddy', species: 'dog' }
  ]
};

const inserted = await Person.query()
  .insertGraphAndFetch(graph);

// Insert with existing relations (relate option)
const graphWithExistingMovie = {
  firstName: 'Jane',
  lastName: 'Smith',
  movies: [
    { id: 1 }, // Existing movie to relate
    { title: 'New Movie', year: 2023 } // New movie to insert
  ]
};

await Person.query()
  .insertGraph(graphWithExistingMovie, { relate: true });

// Insert with references
const graphWithRefs = {
  firstName: 'Alice',
  lastName: 'Johnson',
  pets: [
    { '#id': 'fluffy', name: 'Fluffy', species: 'cat' },
    { name: 'Buddy', species: 'dog', bestFriend: { '#ref': 'fluffy' } }
  ]
};

await Person.query()
  .insertGraph(graphWithRefs, { allowRefs: true });

Upsert Graph

Insert or update a model graph, handling both new and existing models.

/**
 * Upsert (insert or update) a graph of models
 * @param graph - Object or array representing the model graph
 * @param options - Upsert graph options
 * @returns QueryBuilder instance
 */
upsertGraph(graph: object | object[], options?: UpsertGraphOptions): QueryBuilder;

/**
 * Upsert graph and return the resulting models
 * @param graph - Object or array representing the model graph
 * @param options - Upsert graph options
 * @returns QueryBuilder instance
 */
upsertGraphAndFetch(graph: object | object[], options?: UpsertGraphOptions): QueryBuilder;

interface UpsertGraphOptions {
  relate?: boolean | string[];
  unrelate?: boolean | string[];
  insertMissing?: boolean | string[];
  update?: boolean | string[];
  noInsert?: boolean | string[];
  noUpdate?: boolean | string[];
  noDelete?: boolean | string[];
  noRelate?: boolean | string[];
  noUnrelate?: boolean | string[];
  allowRefs?: boolean;
}

Usage Examples:

// Basic upsert - update person, insert/update pets
const graph = {
  id: 1, // Existing person
  firstName: 'John Updated',
  pets: [
    { id: 1, name: 'Fluffy Updated' }, // Update existing pet
    { name: 'New Pet', species: 'bird' } // Insert new pet
  ]
};

const result = await Person.query()
  .upsertGraphAndFetch(graph);

// Upsert with relation control
const graphWithOptions = {
  id: 1,
  firstName: 'John',
  pets: [
    { id: 1, name: 'Fluffy' },
    { id: 2, name: 'Buddy' }
  ],
  movies: [
    { id: 5 } // Existing movie to relate
  ]
};

await Person.query()
  .upsertGraph(graphWithOptions, {
    relate: ['movies'], // Only relate movies, don't update them
    unrelate: ['movies'], // Unrelate movies not in the graph
    update: ['pets'], // Allow updating pets
    insertMissing: ['pets'] // Insert missing pets
  });

// Prevent certain operations
await Person.query()
  .upsertGraph(graph, {
    noDelete: true, // Don't delete related models not in graph
    noUpdate: ['movies'], // Don't update movies
    noInsert: ['movies'] // Don't insert new movies
  });

Graph Expression Object

Convert relation expressions to object format for programmatic manipulation.

/**
 * Get the graph expression as an object
 * @returns Object representation of the graph expression
 */
graphExpressionObject(): object;

Graph References

Special properties for creating references within graphs.

// Special graph properties
interface GraphParameters {
  '#dbRef'?: any; // Reference to existing database record
  '#ref'?: string; // Reference to another object in the graph
  '#id'?: string; // ID for this object to be referenced by others
}

Usage Examples:

// Using #dbRef to reference existing records
const graph = {
  firstName: 'John',
  pets: [
    { '#dbRef': 1 }, // Reference existing pet with ID 1
    { name: 'New Pet', species: 'cat' }
  ]
};

// Using #ref and #id for internal references
const graph = {
  firstName: 'Jane',
  pets: [
    { 
      '#id': 'pet1',
      name: 'Fluffy',
      species: 'cat'
    },
    {
      name: 'Buddy',
      species: 'dog',
      playmate: { '#ref': 'pet1' } // Reference to Fluffy
    }
  ]
};

Allow Graph

Restrict which relations can be inserted/updated in graph operations.

/**
 * Allow only specific relations in graph operations
 * @param expression - Relation expression specifying allowed relations
 * @returns QueryBuilder instance
 */
allowGraph(expression: string): QueryBuilder;

Usage Examples:

// Only allow inserting pets, not movies
await Person.query()
  .allowGraph('pets')
  .insertGraph({
    firstName: 'John',
    pets: [{ name: 'Fluffy', species: 'cat' }],
    movies: [{ title: 'Movie' }] // This will be ignored
  });

// Allow nested relations
await Person.query()
  .allowGraph('pets.owner.movies')
  .insertGraph(complexGraph);

// Allow multiple relations
await Person.query()
  .allowGraph('[pets, movies.actors]')
  .insertGraph(graph);

Graph Validation

Control validation during graph operations.

// Options that affect validation
interface GraphOperationOptions {
  skipValidation?: boolean; // Skip JSON schema validation
}

Usage Examples:

// Skip validation for performance
await Person.query()
  .insertGraph(largeGraph, { 
    skipValidation: true 
  });

Transaction Integration

Graph operations work seamlessly with transactions.

Usage Examples:

await Person.transaction(async trx => {
  // All graph operations will be in the same transaction
  const person = await Person.query(trx)
    .insertGraphAndFetch(personGraph);
    
  const updated = await Person.query(trx)
    .upsertGraphAndFetch(updateGraph);
    
  // If any operation fails, all will be rolled back
});

Error Handling

Graph operations can throw various errors for constraint violations.

Usage Examples:

const { ValidationError, DBError } = require('objection');

try {
  await Person.query().insertGraph(invalidGraph);
} catch (error) {
  if (error instanceof ValidationError) {
    console.log('Validation failed:', error.data);
  } else if (error instanceof DBError) {
    console.log('Database constraint violation:', error.message);
  }
}

Types

interface InsertGraphOptions {
  relate?: boolean | string[];
  allowRefs?: boolean;
}

interface UpsertGraphOptions {
  relate?: boolean | string[];
  unrelate?: boolean | string[];
  insertMissing?: boolean | string[];
  update?: boolean | string[];
  noInsert?: boolean | string[];
  noUpdate?: boolean | string[];
  noDelete?: boolean | string[];
  noRelate?: boolean | string[];
  noUnrelate?: boolean | string[];
  allowRefs?: boolean;
}

interface GraphParameters {
  '#dbRef'?: any;
  '#ref'?: string;
  '#id'?: string;
}

type PartialModelGraph<M> = Partial<M> & GraphParameters & {
  [K in keyof M]?: M[K] extends Model 
    ? PartialModelGraph<M[K]>
    : M[K] extends Array<infer U>
      ? U extends Model
        ? PartialModelGraph<U>[]
        : M[K]
      : M[K];
};

Install with Tessl CLI

npx tessl i tessl/npm-objection

docs

expression-builders.md

graph-operations.md

index.md

model-definition.md

query-building.md

relationships.md

transactions.md

utilities.md

validation.md

tile.json