WIP - add contct and contact details

This commit is contained in:
Francisco Gaona
2026-01-12 21:08:47 +01:00
parent f8a3cffb64
commit ca11c8cbe7
19 changed files with 551 additions and 94 deletions

View File

@@ -15,7 +15,11 @@ export class SchemaManagementService {
objectDefinition: ObjectDefinition,
fields: FieldDefinition[],
) {
const tableName = this.getTableName(objectDefinition.apiName);
const tableName = this.getTableName(
objectDefinition.apiName,
objectDefinition.label,
objectDefinition.pluralLabel,
);
// Check if table already exists
const exists = await knex.schema.hasTable(tableName);
@@ -44,8 +48,10 @@ export class SchemaManagementService {
knex: Knex,
objectApiName: string,
field: FieldDefinition,
objectLabel?: string,
pluralLabel?: string,
) {
const tableName = this.getTableName(objectApiName);
const tableName = this.getTableName(objectApiName, objectLabel, pluralLabel);
await knex.schema.alterTable(tableName, (table) => {
this.addFieldColumn(table, field);
@@ -61,8 +67,10 @@ export class SchemaManagementService {
knex: Knex,
objectApiName: string,
fieldApiName: string,
objectLabel?: string,
pluralLabel?: string,
) {
const tableName = this.getTableName(objectApiName);
const tableName = this.getTableName(objectApiName, objectLabel, pluralLabel);
await knex.schema.alterTable(tableName, (table) => {
table.dropColumn(fieldApiName);
@@ -81,11 +89,13 @@ export class SchemaManagementService {
objectApiName: string,
fieldApiName: string,
field: FieldDefinition,
objectLabel?: string,
pluralLabel?: string,
options?: {
skipTypeChange?: boolean; // Skip if type change would lose data
},
) {
const tableName = this.getTableName(objectApiName);
const tableName = this.getTableName(objectApiName, objectLabel, pluralLabel);
const skipTypeChange = options?.skipTypeChange ?? true;
await knex.schema.alterTable(tableName, (table) => {
@@ -105,8 +115,8 @@ export class SchemaManagementService {
/**
* Drop an object table
*/
async dropObjectTable(knex: Knex, objectApiName: string) {
const tableName = this.getTableName(objectApiName);
async dropObjectTable(knex: Knex, objectApiName: string, objectLabel?: string, pluralLabel?: string) {
const tableName = this.getTableName(objectApiName, objectLabel, pluralLabel);
await knex.schema.dropTableIfExists(tableName);
@@ -241,16 +251,35 @@ export class SchemaManagementService {
/**
* Convert object API name to table name (convert to snake_case, pluralize)
*/
private getTableName(apiName: string): string {
// Convert PascalCase to snake_case
const snakeCase = apiName
.replace(/([A-Z])/g, '_$1')
.toLowerCase()
.replace(/^_/, '');
private getTableName(apiName: string, objectLabel?: string, pluralLabel?: string): string {
const toSnakePlural = (source: string): string => {
const cleaned = source.replace(/[\s-]+/g, '_');
const snake = cleaned
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
.replace(/__+/g, '_')
.toLowerCase()
.replace(/^_/, '');
// Simple pluralization (append 's' if not already plural)
// In production, use a proper pluralization library
return snakeCase.endsWith('s') ? snakeCase : `${snakeCase}s`;
if (snake.endsWith('y')) return `${snake.slice(0, -1)}ies`;
if (snake.endsWith('s')) return snake;
return `${snake}s`;
};
const fromApi = toSnakePlural(apiName);
const fromLabel = objectLabel ? toSnakePlural(objectLabel) : null;
const fromPlural = pluralLabel ? toSnakePlural(pluralLabel) : null;
if (fromLabel && fromLabel.includes('_') && !fromApi.includes('_')) {
return fromLabel;
}
if (fromPlural && fromPlural.includes('_') && !fromApi.includes('_')) {
return fromPlural;
}
if (fromLabel && fromLabel !== fromApi) return fromLabel;
if (fromPlural && fromPlural !== fromApi) return fromPlural;
return fromApi;
}
/**