Hello,
Expected behavior
Display a simple relationship table in forestadmin called EndpointEndpointTag.
The table definition (typeorm):
@Entity('endpoint_endpoint_tags_endpoint_tag')
export class EndpointEndpointTag {
@PrimaryGeneratedColumn('uuid')
id?: string;
@ManyToOne(() => Endpoint)
endpoint!: Endpoint;
@Column('uuid')
endpointId!: string;
@ManyToOne(() => EndpointTag)
endpointTag!: EndpointTag;
@Column('uuid')
endpointTagId!: string;
}
The table SQL:
CREATE TABLE "endpoint_endpoint_tags_endpoint_tag" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "endpointId" uuid NOT NULL, "endpointTagId" uuid NOT NULL, CONSTRAINT "PK_578480e08bbbcb2539c619c2f36" PRIMARY KEY ("id"))
ALTER TABLE "endpoint_endpoint_tags_endpoint_tag" ADD CONSTRAINT "FK_607ba4cc41e8bf50c5aee96cbd6" FOREIGN KEY ("endpointId") REFERENCES "endpoint"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
ALTER TABLE "endpoint_endpoint_tags_endpoint_tag" ADD CONSTRAINT "FK_e5392616b464b0dccc440170d19" FOREIGN KEY ("endpointTagId") REFERENCES "endpoint_tag"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
I updated FA models with lumber update
.
The FA model endpoint-endpoint-tags-endpoint-tag.js
:
// This model was generated by Lumber. However, you remain in control of your models.
// Learn how here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/models/enrich-your-models
module.exports = (sequelize, DataTypes) => {
const { Sequelize } = sequelize;
// This section contains the fields of your model, mapped to your table's columns.
// Learn more here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/models/enrich-your-models#declaring-a-new-field-in-a-model
const EndpointEndpointTagsEndpointTag = sequelize.define('endpointEndpointTagsEndpointTag', {
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: Sequelize.literal('uuid_generate_v4()'),
allowNull: false,
},
}, {
tableName: 'endpoint_endpoint_tags_endpoint_tag',
underscored: true,
timestamps: false,
schema: process.env.DATABASE_SCHEMA,
});
// This section contains the relationships for this model. See: https://docs.forestadmin.com/documentation/v/v6/reference-guide/relationships#adding-relationships.
EndpointEndpointTagsEndpointTag.associate = (models) => {
EndpointEndpointTagsEndpointTag.belongsTo(models.endpoint, {
foreignKey: {
name: 'endpointIdKey',
field: 'endpointId',
},
as: 'endpoint',
});
EndpointEndpointTagsEndpointTag.belongsTo(models.endpointTag, {
foreignKey: {
name: 'endpointTagIdKey',
field: 'endpointTagId',
},
as: 'endpointTag',
});
};
return EndpointEndpointTagsEndpointTag;
};
The forest schema:
+ }, {
+ "name": "endpointEndpointTagsEndpointTag",
+ "nameOld": "endpointEndpointTagsEndpointTag",
+ "icon": null,
+ "integration": null,
+ "isReadOnly": false,
+ "isSearchable": true,
+ "isVirtual": false,
+ "onlyForRelationships": false,
+ "paginationType": "page",
+ "fields": [{
+ "field": "endpoint",
+ "type": "String",
+ "defaultValue": null,
+ "enums": null,
+ "integration": null,
+ "isFilterable": true,
+ "isPrimaryKey": false,
+ "isReadOnly": false,
+ "isRequired": false,
+ "isSortable": true,
+ "isVirtual": false,
+ "reference": "endpoint.endpointIdKey",
+ "inverseOf": null,
+ "relationship": "BelongsTo",
+ "validations": []
+ }, {
+ "field": "endpointTag",
+ "type": "String",
+ "defaultValue": null,
+ "enums": null,
+ "integration": null,
+ "isFilterable": true,
+ "isPrimaryKey": false,
+ "isReadOnly": false,
+ "isRequired": false,
+ "isSortable": true,
+ "isVirtual": false,
+ "reference": "endpointTag.endpointTagIdKey",
+ "inverseOf": null,
+ "relationship": "BelongsTo",
+ "validations": []
+ }, {
+ "field": "id",
+ "type": "String",
+ "defaultValue": null,
+ "enums": null,
+ "integration": null,
+ "isFilterable": true,
+ "isPrimaryKey": true,
+ "isReadOnly": false,
+ "isRequired": false,
+ "isSortable": true,
+ "isVirtual": false,
+ "reference": null,
+ "inverseOf": null,
+ "validations": []
+ }],
+ "segments": [],
+ "actions": []
}, {
Actual behavior
The table cannot be displayed on ForestAdmin.
It seems that Forest gives snake case fields to sequelize. I did grep the whole project but no reference for endpoint_tag_id to refer to camelCase fields …
Failure Logs
[forest] 🌳🌳🌳 Unexpected error: column endpointEndpointTagsEndpointTag.endpoint_tag_id does not exist
{
"name": "SequelizeDatabaseError",
"parent": {
"length": 146,
"name": "error",
"severity": "ERROR",
"code": "42703",
"position": "188",
"file": "parse_relation.c",
"line": "3294",
"routine": "errorMissingColumn",
"sql": "SELECT \"endpointEndpointTagsEndpointTag\".\"id\", \"endpointEndpointTagsEndpointTag\".\"endpointId\" AS \"endpointIdKey\", \"endpointEndpointTagsEndpointTag\".\"endpointTagId\" AS \"endpointTagIdKey\", \"endpointEndpointTagsEndpointTag\".\"endpoint_tag_id\" AS \"endpointTagId\", \"endpointEndpointTagsEndpointTag\".\"endpoint_id\" AS \"endpointId\", \"endpoint\".\"id\" AS \"endpoint.id\", \"endpoint\".\"domain\" AS \"endpoint.domain\", \"endpointTag\".\"id\" AS \"endpointTag.id\", \"endpointTag\".\"name\" AS \"endpointTag.name\" FROM \"public\".\"endpoint_endpoint_tags_endpoint_tag\" AS \"endpointEndpointTagsEndpointTag\" LEFT OUTER JOIN \"public\".\"endpoint\" AS \"endpoint\" ON \"endpointEndpointTagsEndpointTag\".\"endpointId\" = \"endpoint\".\"id\" LEFT OUTER JOIN \"public\".\"endpoint_tag\" AS \"endpointTag\" ON \"endpointEndpointTagsEndpointTag\".\"endpointTagId\" = \"endpointTag\".\"id\" ORDER BY \"endpointEndpointTagsEndpointTag\".\"id\" DESC LIMIT 15 OFFSET 0;"
},
"original": {
"length": 146,
"name": "error",
"severity": "ERROR",
"code": "42703",
"position": "188",
"file": "parse_relation.c",
"line": "3294",
"routine": "errorMissingColumn",
"sql": "SELECT \"endpointEndpointTagsEndpointTag\".\"id\", \"endpointEndpointTagsEndpointTag\".\"endpointId\" AS \"endpointIdKey\", \"endpointEndpointTagsEndpointTag\".\"endpointTagId\" AS \"endpointTagIdKey\", \"endpointEndpointTagsEndpointTag\".\"endpoint_tag_id\" AS \"endpointTagId\", \"endpointEndpointTagsEndpointTag\".\"endpoint_id\" AS \"endpointId\", \"endpoint\".\"id\" AS \"endpoint.id\", \"endpoint\".\"domain\" AS \"endpoint.domain\", \"endpointTag\".\"id\" AS \"endpointTag.id\", \"endpointTag\".\"name\" AS \"endpointTag.name\" FROM \"public\".\"endpoint_endpoint_tags_endpoint_tag\" AS \"endpointEndpointTagsEndpointTag\" LEFT OUTER JOIN \"public\".\"endpoint\" AS \"endpoint\" ON \"endpointEndpointTagsEndpointTag\".\"endpointId\" = \"endpoint\".\"id\" LEFT OUTER JOIN \"public\".\"endpoint_tag\" AS \"endpointTag\" ON \"endpointEndpointTagsEndpointTag\".\"endpointTagId\" = \"endpointTag\".\"id\" ORDER BY \"endpointEndpointTagsEndpointTag\".\"id\" DESC LIMIT 15 OFFSET 0;"
},
"sql": "SELECT \"endpointEndpointTagsEndpointTag\".\"id\", \"endpointEndpointTagsEndpointTag\".\"endpointId\" AS \"endpointIdKey\", \"endpointEndpointTagsEndpointTag\".\"endpointTagId\" AS \"endpointTagIdKey\", \"endpointEndpointTagsEndpointTag\".\"endpoint_tag_id\" AS \"endpointTagId\", \"endpointEndpointTagsEndpointTag\".\"endpoint_id\" AS \"endpointId\", \"endpoint\".\"id\" AS \"endpoint.id\", \"endpoint\".\"domain\" AS \"endpoint.domain\", \"endpointTag\".\"id\" AS \"endpointTag.id\", \"endpointTag\".\"name\" AS \"endpointTag.name\" FROM \"public\".\"endpoint_endpoint_tags_endpoint_tag\" AS \"endpointEndpointTagsEndpointTag\" LEFT OUTER JOIN \"public\".\"endpoint\" AS \"endpoint\" ON \"endpointEndpointTagsEndpointTag\".\"endpointId\" = \"endpoint\".\"id\" LEFT OUTER JOIN \"public\".\"endpoint_tag\" AS \"endpointTag\" ON \"endpointEndpointTagsEndpointTag\".\"endpointTagId\" = \"endpointTag\".\"id\" ORDER BY \"endpointEndpointTagsEndpointTag\".\"id\" DESC LIMIT 15 OFFSET 0;",
"stack": "SequelizeDatabaseError: column endpointEndpointTagsEndpointTag.endpoint_tag_id does not exist\n at Query.formatError (/usr/src/app/node_modules/sequelize/lib/dialects/postgres/query.js:354:16)\n at query.catch.err (/usr/src/app/node_modules/sequelize/lib/dialects/postgres/query.js:71:18)\n at tryCatcher (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/util.js:16:23)\n at Promise._settlePromiseFromHandler (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:547:31)\n at Promise._settlePromise (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:604:18)\n at Promise._settlePromise0 (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:649:10)\n at Promise._settlePromises (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/promise.js:725:18)\n at _drainQueueStep (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/async.js:93:12)\n at _drainQueue (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/async.js:86:9)\n at Async._drainQueues (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/async.js:102:5)\n at Immediate.Async.drainQueues [as _onImmediate] (/usr/src/app/node_modules/sequelize/node_modules/bluebird/js/release/async.js:15:14)\n at runCallback (timers.js:705:18)\n at tryOnImmediate (timers.js:676:5)\n at processImmediate (timers.js:658:5)"
Thank you a lot for your help.