logo
Skip to Main Content

Properties

  • Source:src/packages/database/model/index.js:553

    The name of the corresponding database table for the model.

  • Source:src/packages/database/model/index.js:117

    An object where you declare hasOne relationships.

    When declaring a relationship you must specify the inverse of the relationship.

    class User extends Model {
      static hasOne = {
        profile: {
          inverse: 'user'
          // The line above lets Lux know that this relationship is accessible
          // on profile instances via `profile.user`.
        }
      };
    }
    
    class Profile extends Model {
      static belongsTo = {
        user: {
          inverse: 'profile'
          // The line above lets Lux know that this relationship is accessible
          // on user instances via `user.profile`.
        }
      };
    }
    

    If the name of the model is different than the key of the relationship, you must specify it in the relationship object.

    class Profile extends Model {
      static belongsTo = {
        owner: {
          inverse: 'profile',
          model: 'user'
          // The line above lets Lux know that this is a relationship with the
          // `User` model and not a non-existent `Owner` model.
        }
      };
    }
    
  • Source:src/packages/database/model/index.js:169

    An object where you declare hasMany relationships.

    When declaring a relationship you must specify the inverse of the relationship.

    class Author extends Model {
      static hasMany = {
        books: {
          inverse: 'author'
          // The line above lets Lux know that this relationship is accessible
          // on book instances via `book.author`.
        }
      };
    }
    
    class Book extends Model {
      static belongsTo = {
        author: {
          inverse: 'books'
          // The line above lets Lux know that this relationship is accessible
          // on author instances via `author.books`.
        }
      };
    }
    

    If the name of the model is different than the key of the relationship, you must specify it in the relationship object.

    class Author extends Model {
      static hasMany = {
        publications: {
          inverse: 'author',
          model: 'book'
          // The line above lets Lux know that this is a relationship with the
          // `Book` model and not a non-existent `Publication` model.
        }
      };
    }
    
    Many to Many

    In the examples above there is only one owner of relationship. Sometimes we need to express a many to many relationship. Typically in relational databases, this is done with a join table. When declaring a many to many relationship that uses a join table, you must specify the join model.

    class Categorization extends Model {
      static belongsTo = {
        tag: {
          inverse: 'categorization'
        },
        post: {
          inverse: 'categorization'
        }
      }
    }
    
    class Tag extends Model {
      static hasMany = {
        posts: {
          inverse: 'tags',
          through: 'categorizations'
        }
      };
    }
    
    class Post extends Model {
      static hasMany = {
        tags: {
          inverse: 'posts',
          through: 'categorizations'
        }
      };
    }
    
  • Source:src/packages/database/model/index.js:326

    An object where you declare validations for an instance's attributes.

    Before a model instance is saved, validations declared in this block are executed. To declare a validation for a model attribute, simply add the attribute name as a key to the validates object. The value for the attribute key should be a function that takes a single argument (the value to validate against) and return a boolean value represent whether or not the attribute is valid.

    class User extends Model {
      static validates {
        username: value => /^\w{2,30}$/.test(value),
        password: value => String(value).length >= 8
      };
    }
    

    In the spirit of have a small api surface area, Lux provides no validation helper functions. You can roll your own helpers with or use one of the many excellent validation libraries like validator.

    import { isEmail } from 'validator';
    
    class User extends Model {
      static validates {
        email: isEmail
      };
    }
    
  • Source:src/packages/database/model/index.js:543

    A reference to the application's logger.

  • Source:src/packages/database/model/index.js:64

    A timestamp representing when the Model instance was created.

  • Source:src/packages/database/model/index.js:573

    The name of the resource the model represents.

  • Source:src/packages/database/model/index.js:583

    The column name to use for a model's primary key.

  • Source:src/packages/database/model/index.js:259

    An object where you declare belongsTo relationships.

    When declaring a relationship you must specify the inverse of the relationship.

    class Book extends Model {
      static belongsTo = {
        author: {
          inverse: 'books'
          // The line above lets Lux know that this relationship is accessible
          // on author instances via `author.books`.
        }
      };
    }
    
    class Author extends Model {
      static hasMany = {
        books: {
          inverse: 'book'
          // The line above lets Lux know that this relationship is accessible
          // on book instances via `book.author`.
        }
      };
    }
    

    If the name of the model is different than the key of the relationship, you must specify it in the relationship object.

    class Book extends Model {
      static belongsTo = {
        writer: {
          inverse: 'books',
          model: 'author'
          // The line above lets Lux know that this is a relationship with the
          // `Author` model and not a non-existent `Writer` model.
        }
      };
    }
    

    Sometimes our foreign keys in the database do not follow conventions (i.e author_id). You have the option to manually specify foreign keys when a situation like this occurs.

    class Book extends Model {
      static belongsTo = {
        author: {
          inverse: 'books',
          foreignKey: 'SoMe_UnCoNvEnTiOnAl_FoReIgN_KeY'
        }
      };
    }
    
  • Source:src/packages/database/model/index.js:796
  • Source:src/packages/database/model/index.js:820
  • Source:src/packages/database/model/index.js:367

    An object where you declare custom query scopes for the model.

    Scopes allow you to DRY up query logic by chaining custom set's of queries with built-in query method such as where, not, page, etc. To declare a scope, add it as a method on the scopes object.

    class Post extends Model {
      static hasMany = {
        tags: {
          inverse: 'posts'
        },
        comments: {
          inverse: 'post'
        }
      };
    
      static belongsTo = {
        user: {
          inverse: 'posts'
        }
      };
    
      static scopes = {
        isPublic() {
          return this.where({
            isPublic: true
          });
        },
    
        byUser(user) {
          return this.where({
            userId: user.id
          });
        },
    
        withEverything() {
          return this.includes('tags', 'user', 'comments');
        }
      };
    }
    

    Given the scopes declared in the example above, here is how we could return all the public posts with relationships eager loaded for the user with the id of 1.

    const user = await User.find(1);
    
    return Post
      .byUser(user)
      .isPublic()
      .withEverything();
    

    Since scopes can be chained with built-in query methods, we can easily paginate this collection.

    const user = await User.find(1);
    
    return Post
      .byUser(user)
      .isPublic()
      .withEverything()
      .page(1);
    
  • Source:src/packages/database/model/index.js:445

    An object where you declare hooks to execute at certain times in a model instance's lifecycle.

    There are many lifecycle hooks that are executed through out a model instance's lifetime. The have many use cases such as sanitization of attributes, creating dependent relationships, hashing passwords, and much more.

    Execution Order

    When creating a record.

    1. beforeValidation
    2. afterValidation
    3. beforeCreate
    4. beforeSave
    5. afterCreate
    6. afterSave

    When updating a record.

    1. beforeValidation
    2. afterValidation
    3. beforeUpdate
    4. beforeSave
    5. afterUpdate
    6. afterSave

    When deleting a record.

    1. beforeDestroy
    2. afterDestroy
    Anatomy

    Hooks are async functions that are called with two arguments. The first argument is the record that the hook applies to and the second argument is the transaction object relevant to the method from which the hook was called.

    The only time you will need to use the transaction object is if you are creating, updating, or deleting different record(s) within the hook. Using the transaction object when modifying the database in a hook ensures that any modifications made within the hook will be rolled back if the function that initiated the transaction fails.

    import Notification from 'app/models/notification';
    
    class Comment extends Model {
      static belongsTo = {
        post: {
          inverse: 'comments'
        },
        user: {
          inverse: 'comments'
        }
      };
    
      static hooks = {
        async afterCreate(comment, trx) {
          let [post, commenter] = await Promise.all([
            comment.post,
            comment.user
          ]);
    
          const commentee = await post.user;
    
          post = post.title;
          commenter = commenter.name;
    
          // Calling .transacting(trx) prevents the commentee from getting a
          // notification if the comment fails to be persisted in the database.
          await Notification
            .transacting(trx)
            .create({
              user: commentee,
              message: `${commenter} commented on your post "${post}"`
            });
        },
    
        async afterSave() {
          // Good thing you called transacting in afterCreate.
          throw new Error('Fatal Error');
        }
      };
    }
    
  • Source:src/packages/database/model/index.js:730

    Indicates if the model is dirty.

    import Post from 'app/models/post';
    
    Post
     .find(1)
     .then(post => {
        post.isDirty;
        // => false
    
        post.isPublic = true;
    
        post.isDirty;
        // => true
    
        return post.save();
      })
      .then(post => {
        post.isDirty;
        // => false
      });
    
  • Source:src/packages/database/model/index.js:697

    Indicates if the model is new.

    import Post from 'app/models/post';
    
    let post = new Post({
      body: '',
      title: 'New Post',
      isPublic: false
    });
    
    post.isNew;
    // => true
    
    Post.create({
      body: '',
      title: 'New Post',
      isPublic: false
    }).then(post => {
      post.isNew;
      // => false;
    });
    
  • Source:src/packages/database/model/index.js:563

    The canonical name of the model.

  • Source:src/packages/database/model/index.js:46

    The canonical name of a Model's constructor.

  • Source:src/packages/database/model/index.js:763

    Indicates if the model is persisted.

    import Post from 'app/models/post';
    
    Post
     .find(1)
     .then(post => {
        post.persisted;
        // => true
    
        post.isPublic = true;
    
        post.persisted;
        // => false
    
        return post.save();
      })
      .then(post => {
        post.persisted;
        // => true
      });
    
  • Source:src/packages/database/model/index.js:55

    The name of the API resource a Model instance's constructor represents.

  • Source:src/packages/database/model/index.js:36

    The name of the corresponding database table for a Model instance's constructor.

  • Source:src/packages/database/model/index.js:73

    A timestamp representing the last time the Model instance was updated.

Methods

  • Source:src/packages/database/model/index.js:1396

    Check if a value is an instance of a model.

    Parameters
    • value: Any

      The value in question.

    Return Value
  • Source:src/packages/database/model/index.js:1383

    Check if a model has a scope.

    Parameters
    • name: String

      The name of the scope to look for.

    Return Value
  • Source:src/packages/database/model/index.js:1262

    Manually begin a new transaction.

    Most of the time, you don't need to start transactions yourself. However, the transaction method can be useful if you need to do something like bulk creating records.

    await Post.transaction(trx => {
      return Promise.all([
        Post.transacting(trx).create({
          // ...props
        }),
        Post.transacting(trx).create({
          // ...props
        })
      ]);
    });
    
    Parameters
    • The function used for executing the tranasction. This function is called with a new transaction object as it's only argument and is expected to return a promise.

    Return Value

    Resolves with the resolved value of the fn param.

  • Source:src/packages/database/model/index.js:1224

    Specify the transaction object to use for following save, update, or destroy method calls.

    When you call a method like update or destroy, lux will create a transaction and wrap the internals of the method and other downstream method calls like model hooks within. In some edge cases it can be more useful to manually initiate the transaction. Bulk updating or destroying are good examples of this. When you manually begin a transaction, you can call this method to specify the transaction object that you would like to use for calls to the static create method so lux knows not to automatically begin a new transaction if/when the static create method is called.

    // This call to create uses the transaction that lux will initiate.
    await Post.create();
    
    await Post.transaction(trx => {
      // This call to create uses the transaction that we created with the
      // call to the transaction method.
      return Post
        .transacting(trx)
        .create();
    });
    
    Parameters
    • transaction: Transaction

      A transaction object to forward to create method calls.

    Return Value

    Returns a proxied version of this that delagates the transaction param to subsquent create method calls.

  • Source:src/packages/database/model/index.js:1152

    Create and persist a new instance of the model.

    Parameters
    • properties: Object

      An object containing key, value pairs of the attributes and/or relationships you would like to assign to the instance.

    Return Value

    Resolves with the newly created model.

  • Source:src/packages/database/model/index.js:1072

    Permanently delete the instance from the database.

    Parameters
      Return Value

      Resolves with this.

    • Source:src/packages/database/model/index.js:1097

      Reload the record from the database.

      Parameters
        Return Value

        Resolves with this.

      • Source:src/packages/database/model/index.js:1112

        Rollback attributes and relationships to the last known persisted set of values.

        Parameters
          Return Value

          Returns this.

        • Source:src/packages/database/model/index.js:955

          Persist any unsaved changes to the database.

          const post = await Post.first();
          
          console.log(post.title, post.isDirty);
          // => 'New Post' false
          
          post.title = 'How to Save a Lux Model';
          
          console.log(post.title, post.isDirty);
          // => 'How to Update a Lux Model' true
          
          await post.save();
          
          console.log(post.title, post.isDirty);
          // => 'How to Save a Lux Model' false
          
          Parameters
            Return Value

            Resolves with this.

          • Source:src/packages/database/model/index.js:877

            Specify the transaction object to use for following save, update, or destroy method calls.

            When you call a method like update or destroy, lux will create a transaction and wrap the internals of the method and other downstream method calls like model hooks within. In some edge cases it can be more useful to manually initiate the transaction. Bulk updating or destroying are good examples of this. When you manually begin a transaction, you can call this method to specify the transaction object that you would like to use for subsequent mutation methods (save, update, destroy, etc.) so lux knows not to automatically begin a new transaction if/when a mutation method is called.

            const post = await Post.first();
            
            // This call to update uses the transaction that lux will initiate.
            await post.update({
              // updates to post...
            });
            
            await post.transaction(trx => {
              // This call to update uses the transaction that we created with the
              // call to the transaction method.
              return post
                .transacting(trx)
                .update({
                  // updates to post...
                });
            });
            
            Parameters
            • transaction: Transaction

              A transaction object to forward to save, update, or destroy method calls.

            Return Value

            Returns a proxied version of this that delagates the transaction param to subsquent save, update, or destroy method calls.

          • Source:src/packages/database/model/index.js:921

            Manually begin a new transaction.

            Most of the time, you don't need to start transactions yourself. However, if you need to do something like implement bulk updating of related records the transaction method can be useful.

            const post = await Post.first().include('user');
            const user = await post.user;
            
            await post.transaction(trx => {
              return Promise.all([
                post.transacting(trx).update({
                  // updates to post...
                }),
                user.transacting(trx).update({
                  // updates to user...
                })
              ]);
            });
            
            Parameters
            • The function used for executing the tranasction. This function is called with a new transaction object as it's only argument and is expected to return a promise.

            Return Value

            Resolves with the resolved value of the fn param.

          • Source:src/packages/database/model/index.js:983

            Assign values to the instance and persist any changes to the database.

            const post = await Post.first();
            
            console.log(post.title, post.isPublic, post.isDirty);
            // => 'New Post' false false
            
            await post.update({
              title: 'How to Update a Lux Model',
              isPublic: true
            });
            
            console.log(post.title, post.isPublic, post.isDirty);
            // => 'How to Update a Lux Model' true false
            
            Parameters
            • properties: Object

              An object containing key, value pairs of the attributes and/or relationships you would like to assign to the instance.

            Return Value

            Resolves with this.