@vaadin/hilla-react-crud
Version:
Hilla CRUD utils for React
139 lines • 4.92 kB
JavaScript
import { BooleanModel, NumberModel, StringModel, _meta, createDetachedModel, EnumModel, ObjectModel, } from '@vaadin/hilla-lit-form';
const javaTypeMap = {
byte: 'integer',
'java.lang.Byte': 'integer',
short: 'integer',
'java.lang.Short': 'integer',
int: 'integer',
'java.lang.Integer': 'integer',
long: 'integer',
'java.lang.Long': 'integer',
float: 'decimal',
'java.lang.Float': 'decimal',
double: 'decimal',
'java.lang.Double': 'decimal',
'java.time.LocalDate': 'date',
'java.time.LocalTime': 'time',
'java.time.OffsetTime': 'time',
'java.time.LocalDateTime': 'datetime',
'java.time.OffsetDateTime': 'datetime',
'java.time.ZonedDateTime': 'datetime',
'java.util.Date': 'datetime',
'java.sql.Date': 'datetime',
};
function determinePropertyType(model) {
const { javaType } = model[_meta];
const propertyType = javaType ? javaTypeMap[javaType] : undefined;
if (propertyType) {
return propertyType;
}
if (model instanceof StringModel) {
return 'string';
}
else if (model instanceof NumberModel) {
return 'decimal';
}
else if (model instanceof BooleanModel) {
return 'boolean';
}
else if (model instanceof EnumModel) {
return 'enum';
}
else if (model instanceof ObjectModel) {
return 'object';
}
return undefined;
}
export function hasAnnotation(meta, annotationName) {
return meta.annotations?.some((annotation) => annotation.name === annotationName) ?? false;
}
export function _generateHeader(path) {
return path
.substring(path.lastIndexOf('.') + 1)
.replace(/([A-Z])/gu, '-$1')
.toLowerCase()
.replace(/-/gu, ' ')
.replace(/^./u, (match) => match.toUpperCase());
}
const getPropertyNames = (model) => {
const propertyNames = [];
for (let proto = model; proto !== ObjectModel; proto = Object.getPrototypeOf(proto)) {
propertyNames.unshift(...Object.keys(Object.getOwnPropertyDescriptors(proto.prototype)).filter((p) => p !== 'new'));
}
return propertyNames;
};
export class ModelInfo {
modelInstance;
idProperty;
constructor(model, idPropertyName) {
this.modelInstance = createDetachedModel(model);
this.idProperty = ModelInfo.resolveIdProperty(this, idPropertyName);
}
static resolveIdProperty(modelInfo, idPropertyName) {
if (idPropertyName) {
return modelInfo.getProperty(idPropertyName);
}
const rootProperties = modelInfo.getRootProperties();
let idProperty = rootProperties.find((propertyInfo) => hasAnnotation(propertyInfo.meta, 'jakarta.persistence.Id'));
idProperty ??= rootProperties.find((propertyInfo) => propertyInfo.name === 'id');
return idProperty;
}
static resolvePropertyModel(modelInstance, path) {
const parts = path.split('.');
let currentModel = modelInstance;
for (const part of parts) {
if (!currentModel || !(currentModel instanceof ObjectModel)) {
return undefined;
}
currentModel = currentModel[part];
}
return currentModel;
}
getRootProperties(path) {
const model = path ? ModelInfo.resolvePropertyModel(this.modelInstance, path) : this.modelInstance;
if (!model) {
return [];
}
return getPropertyNames(model.constructor)
.map((name) => {
const effectivePath = path ? `${path}.${name}` : name;
return this.getProperty(effectivePath);
})
.filter(Boolean);
}
getProperty(path) {
const propertyModel = ModelInfo.resolvePropertyModel(this.modelInstance, path);
if (!propertyModel?.[_meta]) {
return undefined;
}
const pathParts = path.split('.');
const name = pathParts[pathParts.length - 1];
const meta = propertyModel[_meta];
const humanReadableName = _generateHeader(name);
const type = determinePropertyType(propertyModel);
return {
name: path,
humanReadableName,
type,
meta,
model: propertyModel,
};
}
getProperties(paths) {
return paths.map((path) => this.getProperty(path)).filter(Boolean);
}
}
export function getDefaultProperties(modelInfo) {
const properties = modelInfo.getRootProperties();
return (properties
.flatMap((prop) => {
if (hasAnnotation(prop.meta, 'jakarta.persistence.OneToOne')) {
return modelInfo.getRootProperties(prop.name);
}
return prop;
})
.filter((prop) => !!prop.type &&
!(hasAnnotation(prop.meta, 'jakarta.persistence.Id') ||
hasAnnotation(prop.meta, 'jakarta.persistence.Version'))));
}
//# sourceMappingURL=model-info.js.map