// How the real server describes a Genesis field type on the wire: the JSON // type a value travels as, the JVM class its generated DAO property has, and // the names it derives from table and field names. Checked against GSF // 8.15.29 recordings (test/conformance/recordings/showcase-real/meta-*.json, // json-schema-*.json) and genesis-process's PALMetadataUtils.kt. // The JSON type each Genesis type travels as. Dates are epoch millis and // BigDecimals are strings, so a client must not read the Genesis type as the // JSON one. const JSON_TYPES: Record = { STRING: 'string', ENUM: 'string', INT: 'integer', SHORT: 'integer', LONG: 'integer', DOUBLE: 'number', BIGDECIMAL: 'string', BOOLEAN: 'boolean', DATE: 'integer', DATETIME: 'integer', NANO_TIMESTAMP: 'integer', RAW: 'string', // A DTO's nested types (dtoTypes.ts): GSF's MetaFieldType jsonType. ARRAY: 'array', MAP: 'object', OBJECT: 'object', ANY: '{}', }; // The JVM class of the generated DAO property, which the real server puts in // DESCRIPTION / description. foundation-forms recognises a date field by // 'org.joda.time.DateTime' (jsonforms/testers/isDate.ts). const JVM_CLASSES: Record = { STRING: 'kotlin.String', INT: 'kotlin.Int', SHORT: 'kotlin.Short', LONG: 'kotlin.Long', DOUBLE: 'kotlin.Double', BIGDECIMAL: 'java.math.BigDecimal', BOOLEAN: 'kotlin.Boolean', DATE: 'org.joda.time.DateTime', DATETIME: 'org.joda.time.DateTime', NANO_TIMESTAMP: 'kotlin.Long', RAW: 'kotlin.ByteArray', }; // Value ranges the DAO's generated annotations carry, reported as MIN/MAX in // event META and minimum/maximum in event JSON schemas. LONG is bounded by // JavaScript's safe integers, not by Long.MAX_VALUE. const INT_MIN = -2147483648; const INT_MAX = 2147483647; const SHORT_MIN = -32768; const SHORT_MAX = 32767; const RANGES: Record = { INT: [INT_MIN, INT_MAX], SHORT: [SHORT_MIN, SHORT_MAX], LONG: [-Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], NANO_TIMESTAMP: [-Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], DOUBLE: [-Number.MAX_VALUE, Number.MAX_VALUE], }; // What the real event schema puts on a BigDecimal property instead of a // genesisType. export const BIGDECIMAL_PATTERN = '[0-9]+(\\.[0-9]+)?'; export function jsonTypeOf(type: string): string { return JSON_TYPES[type] ?? 'string'; } // The types GSF's dictionary gives a `metadata { min; max }` // (FieldMetadata.Number @v8.15.29). const DECLARED_RANGE_TYPES = new Set(['INT', 'SHORT', 'LONG', 'DOUBLE']); // A number field's range: its declared min / max, else its type's. export function rangeOf(field: { type: string; min?: number; max?: number; }): [number, number] | undefined { const range = RANGES[field.type]; if (!range || !DECLARED_RANGE_TYPES.has(field.type)) return range; return [field.min ?? range[0], field.max ?? range[1]]; } // TYPE in event META follows the JVM class, not the dictionary: a DATE column // is a DateTime property, so it is TYPE 'DATETIME' (GENESIS_TYPE says 'DATE'). export function eventMetaTypeOf(type: string): string { if (type === 'DATE') return 'DATETIME'; if (type === 'NANO_TIMESTAMP') return 'LONG'; return type; } // 'COUNTERPARTY_ID' -> 'Counterparty Id', the TITLE the DAO generator gives. export function titleCase(name: string): string { return name .split('_') .filter(Boolean) .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) .join(' '); } // 'ALL_TYPES' -> 'AllTypes', the generated class name. export function pascalCase(name: string): string { return titleCase(name).replace(/ /g, ''); } // The generated DAO class an event's DETAILS deserialize into. export function daoClassOf(table: string): string { return `global.genesis.gen.dao.${pascalCase(table)}`; } // The generated entity class of a view (ViewEntityGenerator.kt PACKAGE_NAME, // GSF v8.15.29): what a request server over the view names in // PARAMETRIC_TYPE. export function viewEntityClassOf(view: string): string { return `global.genesis.gen.view.entity.${pascalCase(view)}`; } // The generated enum class of an ENUM column. export function enumClassOf(table: string | undefined, field: string, appName?: string): string { const segments = ['global.genesis.gen.dao.enums']; if (appName) segments.push(appName); if (table) segments.push(table.toLowerCase()); segments.push(pascalCase(field)); return segments.join('.'); } export function jvmClassOf(type: string, enumClass: () => string): string { if (type === 'ENUM') return enumClass(); return JVM_CLASSES[type] ?? 'kotlin.String'; }