Sutando ORM

repository·main·Indexed 43 days ago

https://github.com/sutandojs/sutando

A modern Node.js object-relational mapper (ORM) inspired by Laravel's Eloquent. It provides a query builder and model-based interaction for MySQL, PostgreSQL, MSSql, MariaDB, and SQLite. Features include pagination, eager loading, a CLI for migrations and model generation, and a Collection class for managing model instances.

Tokens
13.7K
Snippets
57
Records
63
Agent score
52%

What's inside Sutando

  1. Use Sutando Models (ORM)

    main

    Sutando's ORM maps database tables to classes that extend Model. This allows for more intuitive data manipulation, including querying, saving, and deleting records.

    class User extends Model {}
    
    // Querying via Model
    const users = await User.query().where('age', '>', 35).get();
    
    // Inserting a new record
    const user = new User;
    user.name = 'David Bowie';
    await user.save();
    
    // Deleting a record
    await user.delete();
  2. Configure a database connection with sutando.addConnection()

    main

    Before performing database operations, you must register your connection details using sutando.addConnection(). This method accepts a configuration object specifying the client (the database driver) and a connection object containing host, port, user, password, and database name.

    const { sutando, Model } = require('sutando');
    
    sutando.addConnection({
      client: 'mysql2',
      connection: {
        host : '127.0.0.1',
        port : 3306,
        user : 'root',
        password : '',
        database : 'test'
      },
    });
    
    const db = sutando.connection();
  3. Perform Pagination and Eager Loading with Models

    main

    Sutando models support advanced querying features like pagination and eager loading to handle relationships efficiently.

    • Pagination: Use .paginate() on a query.
    • Eager Loading: Use .with('relationName') to load related models in a single query.
    • Constrained Eager Loading: Pass a callback to .with() to filter the related models being loaded.
    • Lazy Eager Loading: Use .load('relationName') on an existing model instance to load its relations.
    // Pagination
    const users = await User.query().paginate();
    
    // Eager Loading
    const users = await User.query().with('posts').get();
    
    // Constraining Eager Loads
    const users = await User.query().with({
      posts: q => q.where('likes_count', '>', 100)
    }).get();
    
    // Lazy Eager Loading
    await user.load('posts');
  4. Manage model sets with the Collection class

    main
    The Collection class is used to manage sets of model instances. It extends BaseCollection (from collect.js) and provides specialized methods for working with models that implement a getKey() method. It supports common collection operations like mapping, filtering, and finding, while also providing model-specific utilities like visibility management and data serialization.
  5. Manage relationships with Relation classes

    main

    Sutando provides specialized classes to handle different types of database relationships. These are typically defined within a Model class.

    • HasOne<M>: A one-to-one relationship where the current model holds the foreign key.
    • HasMany<M>: A one-to-many relationship.
    • BelongsTo<M>: A relationship where the current model holds the foreign key pointing to another model.
    • BelongsToMany<M>: A many-to-many relationship using a pivot table. Supports pivot-specific filtering via wherePivot(...) and orderByPivot(...).
    // Example of defining a relationship in a Model
    class Post extends Model {
      posts() {
        return this.hasMany(Comment);
      }
    }
    
    class Comment extends Model {
      post() {
        return this.belongsTo(Post);
      }
    }
    
    // Accessing relationships
    const post = await Post.query().find(1);
    const comments = await post.posts().getResults();
  6. Extend Models using Plugins and Mixins

    main

    Sutando supports a plugin system to extend Model functionality.

    • Plugin: A function that takes a Model class and returns an extended version of it.
    • MixinFunction: A utility used to compose multiple plugins onto a model class using compose(modelClass, ...plugins).

    This allows you to add shared behaviors (like soft deletes or auditing) to multiple models.

    import { Model, Plugin, compose } from 'sutando';
    
    const myPlugin: Plugin = (BaseModel) => {
      return class extends BaseModel {
        customMethod() { return 'hello'; }
      };
    };
    
    class User extends compose(Model, myPlugin) {}
    
    const user = new User();
    console.log(user.customMethod());
  7. Initialize a new Sutando configuration

    main

    Run the init command to create a fresh sutando.config.js file in your current working directory using the default stub. This is required before running most other CLI commands like migrations or model generation.

    sutando init
  8. Use the Database Query Builder

    main

    The Query Builder allows you to construct SQL queries using JavaScript methods without needing to define a Model class. You can access the builder via sutando.connection().table('tableName').

    const db = sutando.connection();
    const users = await db.table('users').where('age', '>', 35).get();
  9. Implement a HasMany relationship

    main

    The HasMany class is used to define a one-to-many relationship between a parent entity and multiple related entities. It extends the base Relation class and requires a foreignKey (the key on the related objects pointing back to the parent) and a localKey (the key on the parent object used for the match). When instantiated, it returns a proxy object representing the relationship.

    const HasMany = require('./has-many');
    
    // Usage pattern:
    // new HasMany(related, parent, foreignKey, localKey);
  10. Create a new database migration with MigrationCreator

    main

    Use the create method of MigrationCreator to generate a new migration file. The method automatically prefixes the filename with a timestamp in the format YYYY_MM_DD_HHmmss.

    Depending on the arguments provided, it selects different stubs:

    • If table is null: Uses migration-js.stub.
    • If table is provided and create is true: Uses migration.create-js.stub.
    • If table is provided and create is false: Uses migration.update-js.stub.

    If a table name is provided, the stub's DummyTable or {{\s*table\s*}} placeholders are replaced with the actual table name.

    const MigrationCreator = require('./path/to/migration-creator');
    
    // Initialize with a path to custom stubs if available
    const creator = new MigrationCreator('./custom-stubs');
    
    // Create a 'create' migration for a table named 'users'
    const filePath = await creator.create('add_users_table', './migrations', 'users', true);
    
    // Create an 'update' migration for a table named 'users'
    const updatePath = await creator.create('add_email_to_users', './migrations', 'users', false);
  11. Use the BelongsToMany relationship

    main

    The BelongsToMany class implements a many-to-many relationship between two entities via a pivot table. It requires a pivot table name and keys to map the relationship between the parent and the related model.

    When initialized, it returns a proxy object that allows for fluent interaction with the relationship. The relationship configuration includes support for pivot columns, filtering via pivotWheres, and timestamp tracking.

    // Note: This is a conceptual instantiation based on the constructor signature
    const BelongsToMany = require('./belongs-to-many');
    
    const relation = new BelongsToMany(
      relatedModel,      // The model being related to
      parentModel,       // The current model
      'pivot_table',     // The name of the pivot table
      'parent_id',       // The foreign key in the pivot table pointing to the parent
      'related_id',      // The foreign key in the pivot table pointing to the related model
      'id',              // The primary key of the parent model
      'id'               // The primary key of the related model
    );