DEV Community

Discussion on: Using a TypeScript interface to define model properties in Objection.js

tylerlwsmith profile image
Tyler Smith Author

I hope you're able to get it sorted out! Feel free to leave a comment with which one you liked better incase anyone else who is having the same problem stumbles onto this conversation in the future.

Thread Thread
vsamma profile image
Veiko Samma • Edited on

Thanks!
I will.

But first I need to solve some issues. With this "type" solution offered here, I'm immediately running into problems when creating new objects of this new type "Dataset" (based on DatasetModel).

Although it hides most of Model's properties, it still includes QueryBuilderType and when instantiating a new object, this is a required field to add as well. If I don't, I get this error:

Type ... is missing the following properties from type 'ModelObject<DatasetModel>': QueryBuilderType

Edit:

And when I have an example like this:

//project.ts
export class ProjectModel extends Model {
  public id!: number;
  public name!: string;
  public datasets!: DatasetModel[];

  public static tableName = 'projects';

  static get relationMappings() {
    return {
      datasets: {
        relation: Model.HasManyRelation,
        modelClass: DatasetModel,
        join: {
          from: 'projects.id',
          to: 'datasets.project_id',
        },
      }
    };
  }
}

export type Project = ModelObject<ProjectModel>;


//dataset.ts
export class DatasetModel extends Model {
  public id!: number;
  public projectId!: number;

  public static tableName = 'datasets';

  static get relationMappings() {
    return {
      project: {
        relation: Model.BelongsToOneRelation,
        modelClass: ProjectModel,
        join: {
          from: 'datasets.project_id',
          to: 'projects.id',
        },
      },
  }
}

export type Dataset = ModelObject<DatasetModel>;
Enter fullscreen mode Exit fullscreen mode

I'm running into a problem when I want to instantiate a Project object. I need the "datasets" property to be defined for the Project so I can use it on the object (with autocomplete etc), only relationMapping is not enough. But when its type is DatasetModel (which is the only way relatedQuery works), then I also need to explicitly set the ~30 properties that the Model class has as well. Not to mention the fact that then you need to use the DatasetModel class in your business logical (service) layer which means that the DB communication (ORM) implementational details are not decoupled from the rest of the app anymore.

If I use Hunter's solution with the Type and set the "datasets" property to type "Dataset" for the Project class, then I only need to set the value to 1 extra property (QueryBuilderType, as stated above), but this again breaks the usage of relatedQuery and I'm back to square one.

So I think now I have to start trying with the interface "implements" approach.

But it's so crazy how you can't easily define DB model entities, which have other entities as related properties, all based on interface contracts in Typescript and also use all the query functionality properly.