Hi @GuillaumeGautreau,
Thanks you for you fast answer. Here is what you asked:
model_template (which is the one with two relations on the same table: model_instance)
module.exports = (sequelizeClient, DataTypes) => {
const { Sequelize } = sequelizeClient;
const modelTemplate = sequelizeClient.define(
'model_template',
{
familyId: {
type: DataTypes.INTEGER,
allowNull: false,
},
slug: {
type: DataTypes.STRING(64),
unique: true,
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.TEXT,
allowNull: true,
},
prodModelInstanceId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
as: 'Prod Model',
},
betaModelInstanceId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
as: 'Beta Model',
},
},
{
tableName: 'model_template',
schema: database_1.Schemas.IModels,
hooks: {
beforeCount(options) {
options.raw = true;
},
},
}
);
// eslint-disable-next-line no-unused-vars
modelTemplate.associate = function(models) {
// Define associations here
// See http://docs.sequelizejs.com/en/latest/docs/associations/
models.model_template.belongsTo(models.model_template_family, {
foreignKey: 'familyId',
});
models.model_template.belongsTo(models.model_instance, {
foreignKey: 'prodModelInstanceId',
constraints: false,
});
models.model_template.belongsTo(models.model_instance, {
foreignKey: 'betaModelInstanceId',
constraints: false,
});
models.model_template.hasMany(
models.prediction_post_processing_compatibility,
{ foreignKey: 'modelTemplateId', as: 'compats' }
);
};
return modelTemplate;
};
model_instance
const uniqueComposite = 'modelInstanceVersionTemplateId';
module.exports = (sequelizeClient, DataTypes) => {
const { Sequelize } = sequelizeClient;
const modelInstance = sequelizeClient.define(
'model_instance',
{
templateId: {
type: DataTypes.INTEGER,
allowNull: false,
unique: uniqueComposite,
},
version: {
type: DataTypes.STRING(32),
allowNull: false,
unique: uniqueComposite,
},
branchSlug: {
type: DataTypes.STRING(128),
allowNull: false,
},
dockerImageUri: {
type: DataTypes.STRING,
allowNull: true,
},
metadata: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: null,
},
},
{
tableName: 'model_instance',
schema: database_1.Schemas.IModels,
hooks: {
beforeCount(options) {
options.raw = true;
},
},
}
);
// eslint-disable-next-line no-unused-vars
modelInstance.associate = function(models) {
// Define associations here
// See http://docs.sequelizejs.com/en/latest/docs/associations/
models.model_instance.belongsTo(models.model_template, {
foreignKey: 'templateId',
});
};
return modelInstance;
};
SQL
CREATE TABLE imodels.model_template
(
id integer NOT NULL DEFAULT nextval('imodels.model_template_id_seq'::regclass),
"familyId" integer NOT NULL,
slug character varying(64) COLLATE pg_catalog."default" NOT NULL,
name character varying(255) COLLATE pg_catalog."default" NOT NULL,
description text COLLATE pg_catalog."default",
"prodModelInstanceId" integer,
"betaModelInstanceId" integer,
"createdAt" timestamp with time zone NOT NULL,
"updatedAt" timestamp with time zone NOT NULL,
CONSTRAINT model_template_pkey PRIMARY KEY (id),
CONSTRAINT model_template_slug_key UNIQUE (slug)
,
CONSTRAINT "model_template_familyId_fkey" FOREIGN KEY ("familyId")
REFERENCES imodels.model_template_family (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE CASCADE
)
CREATE TABLE imodels.model_instance
(
id integer NOT NULL DEFAULT nextval('imodels.model_instance_id_seq'::regclass),
"templateId" integer NOT NULL,
version character varying(32) COLLATE pg_catalog."default" NOT NULL,
"branchSlug" character varying(128) COLLATE pg_catalog."default" NOT NULL,
metadata json,
"createdAt" timestamp with time zone NOT NULL,
"updatedAt" timestamp with time zone NOT NULL,
"dockerImageUri" character varying(255) COLLATE pg_catalog."default" DEFAULT NULL::character varying,
CONSTRAINT model_instance_pkey PRIMARY KEY (id),
CONSTRAINT unique_imodels_model_instance_version_templateid UNIQUE (version, "templateId")
,
CONSTRAINT "model_instance_templateId_fkey" FOREIGN KEY ("templateId")
REFERENCES imodels.model_template (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE NO ACTION
)
.forestadmin-schema.json
{
"name": "model_instance",
"nameOld": "model_instance",
"icon": null,
"integration": null,
"isReadOnly": false,
"isSearchable": true,
"isVirtual": false,
"onlyForRelationships": false,
"paginationType": "page",
"fields": [{
"field": "branchSlug",
"type": "String",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": true,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": [{
"message": null,
"type": "is present",
"value": null
}]
}, {
"field": "createdAt",
"type": "Date",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "dockerImageUri",
"type": "String",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "id",
"type": "Number",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": true,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "metadata",
"type": "Json",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "model_template",
"type": "Number",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": "model_template.templateId",
"inverseOf": null,
"relationship": "BelongsTo",
"validations": []
}, {
"field": "updatedAt",
"type": "Date",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "version",
"type": "String",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": true,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": [{
"message": null,
"type": "is present",
"value": null
}]
}],
"segments": [],
"actions": []
}, {
"name": "model_template",
"nameOld": "model_template",
"icon": null,
"integration": null,
"isReadOnly": false,
"isSearchable": true,
"isVirtual": false,
"onlyForRelationships": false,
"paginationType": "page",
"fields": [{
"field": "compats",
"type": ["Number"],
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": "prediction_post_processing_compatibility.modelTemplateId",
"inverseOf": null,
"relationship": "HasMany",
"validations": []
}, {
"field": "createdAt",
"type": "Date",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "description",
"type": "String",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "id",
"type": "Number",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": true,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "model_instance",
"type": "Number",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": "model_instance.betaModelInstanceId",
"inverseOf": null,
"relationship": "BelongsTo",
"validations": []
}, {
"field": "model_template_family",
"type": "Number",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": "model_template_family.familyId",
"inverseOf": null,
"relationship": "BelongsTo",
"validations": []
}, {
"field": "name",
"type": "String",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": true,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": [{
"message": null,
"type": "is present",
"value": null
}]
}, {
"field": "prodModelInstanceId",
"type": "Number",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}, {
"field": "slug",
"type": "String",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": true,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": [{
"message": null,
"type": "is present",
"value": null
}]
}, {
"field": "updatedAt",
"type": "Date",
"defaultValue": null,
"enums": null,
"integration": null,
"isFilterable": true,
"isPrimaryKey": false,
"isReadOnly": false,
"isRequired": false,
"isSortable": true,
"isVirtual": false,
"reference": null,
"inverseOf": null,
"validations": []
}],
"segments": [],
"actions": []
}
Best regards,
Guillaume