UNPKG

leds-spark-lib

Version:

Biblioteca de geração de código

203 lines 8.25 kB
import { isEnumX, isImportedEntity, isLocalEntity, isManyToMany, isModule, isModuleImport, getRef, base_ident, capitalizeString, topologicalSort } from "../../../../models/model.js"; const ident = base_ident; export function generateModels(m) { const get_entities_prereqs = (e) => { const superType = getRef(e.superType); if (superType && superType.$container === e.$container && isLocalEntity(superType)) { return [superType]; } return []; }; const sorted_entities = topologicalSort(m.elements.filter(isLocalEntity), get_entities_prereqs); const imports = Array.from(generateImports(m), ([key, value]) => `from ${key} import ${Array.from(value).join(', ')}`); const already_done_entities = new Set(); const lines = [ `from django.db import models`, `from django.utils.translation import gettext_lazy as _`, ...imports, ``, ...m.elements.filter(isEnumX).map(generateEnum), ``, ...sorted_entities.map(e => generateModel(e, already_done_entities)), `` ]; return lines.join('\n'); } /** * Checa dentro das entidades de um módulo para identificar os imports necessários */ function generateImports(m) { const imports = new Map(); const entities = m.elements.filter(isLocalEntity); if (entities.length === 0) { return imports; } const add_import = (key, value) => { const set = imports.get(key); if (set === undefined) { imports.set(key, new Set([value])); } else { set.add(value); } }; add_import('polymorphic.models', 'PolymorphicModel'); for (const e of entities) { // Adiciona nos imports as entidades que vem de outros módulos que são usadas como supertipos const supertype = getRef(e.superType); const supertype_origin = supertype?.$container; if (supertype_origin) { // Se o supertype vem de um ModuleImport if (isModuleImport(supertype_origin)) { add_import(`${supertype_origin.name}.models`, `${supertype.name}`); } // Se o supertype vem de um módulo local diferente else if (supertype_origin !== m) { add_import(`apps.${supertype_origin.name.toLowerCase()}.models`, `${supertype.name}`); } } // Adiciona nos imports todas as entidades de outros módulos que são referênciadas em relações for (const r of e.relations) { const relType = getRef(r.type); const entity_origin = relType?.$container; if (isModuleImport(entity_origin)) { add_import(`${entity_origin.name}.models`, `${relType?.name}`); } if (isModule(entity_origin) && (entity_origin !== m)) { add_import(`apps.${entity_origin.name.toLowerCase()}.models`, `${relType?.name}`); } } // Adiciona nos imports os tipos que são usados por atributos for (const a of e.attributes) { switch (a.type.toLowerCase()) { case 'cpf': add_import('django_cpf_cnpj.fields', 'CPFField'); break; case 'cnpj': add_import('django_cpf_cnpj.fields', 'CNPJField'); break; case 'user': add_import('django.conf', 'settings'); break; } } } return imports; } function generateEnum(e) { const split_on_camelcase = (str) => { return str.replaceAll(/[a-z][A-Z]/g, sub => sub.at(0) + '_' + sub.at(1)); }; const lines = [ `class ${e.name}(models.TextChoices):`, `${ident}"""${e.comment ?? ''}"""`, ...e.attributes.map(a => { const str = split_on_camelcase(a.name).toLowerCase(); return `${ident}${str.toUpperCase()} = '${str.toUpperCase()}', _('${a.fullName ?? capitalizeString(str.replaceAll('_', ' '))}')`; }), `` ]; return lines.join('\n'); } function generateModel(e, set) { const superType = getRef(e.superType); const superTypeName = superType?.name ?? 'PolymorphicModel, models.Model'; const lines = [ `class ${e.name}(${superTypeName}):`, `${ident}'''${e.comment ?? ''}'''`, ``, ...e.attributes.map(k => ident + generateAttribute(k)), ``, ...e.enumentityatributes.map(k => ident + generateEnumAttribute(k)), ``, ...e.relations.map(k => ident + createRelation(k, set)), ``, `${ident}class Meta:`, `${ident}${ident}${e.is_abstract ? 'abstract = True' : `db_table = '${e.name.toLowerCase()}'`}`, `` ]; set.add(e); return lines.join('\n'); } function generateEnumAttribute(e) { let valor = ""; let tamanho = 0; const enumType = getRef(e.type); for (const a of (enumType?.attributes ?? [])) { if (valor === "") { valor = a.name; } if (a.name.length > tamanho) { tamanho = a.name.length; } } return `${e.name} = models.CharField(max_length=${tamanho}, choices=${enumType?.name}.choices, default=${enumType?.name}.${valor.toUpperCase()})`; } function generateAttribute(a) { const fullname = a.fullName !== undefined ? `"${a.fullName}", ` : ``; switch (a.type.toLowerCase()) { case 'string': return `${a.name} = models.CharField(${fullname}max_length=300, null=True, blank=True)`; case 'decimal': return `${a.name} = models.DecimalField(${fullname}max_digits=14, decimal_places=2, null=True, blank=True)`; case 'cnpj': return `${a.name} = CNPJField(${fullname}null=True, blank=True)`; case 'cpf': return `${a.name} = CPFField(${fullname}null=True, blank=True)`; case 'telefone': return `${a.name} = models.CharField(${fullname}max_length=27, null=True, blank=True)`; case 'celular': return `${a.name} = models.CharField(${fullname}max_length=11, null=True, blank=True)`; case 'user': return `${a.name} = models.ForeignKey(settings.AUTH_USER_MODEL, blank=false, null=false, on_delete=models.CASCADE, related_name="user_application_%(class)s")`; case 'datetime': return `${a.name} = models.DateTimeField(${fullname}blank=True)`; case 'url': return `${a.name} = models.URLField(verbose_name=${fullname}blank=True)`; case 'uuid': return `${a.name} = models.${a.type.toUpperCase()}Field(${fullname}blank=True)`; default: return `${a.name} = models.${capitalizeString(a.type)}Field(${fullname}null=True, blank=True)`; } } function createRelation(r, set) { const tgt_entity = getRef(r.type); let tgt_name; // Auto relação if (tgt_entity === r.$container) { tgt_name = "self"; } // Relação com uma entidade externa/importada else if (isImportedEntity(tgt_entity)) { tgt_name = tgt_entity.name; } // Relação com uma entidade de outro módulo else if (tgt_entity?.$container !== r.$container.$container) { tgt_name = `'apps_${tgt_entity?.$container.name.toLowerCase()}.${tgt_entity?.name}'`; } // Relação interna ao módulo, com uma entidade já declarada else if (isLocalEntity(tgt_entity) && set.has(tgt_entity)) { tgt_name = tgt_entity.name; } // Relação interna ao módulo, com uma entidade ainda não declarada else { tgt_name = `'${tgt_entity?.name}'`; } if (isManyToMany(r)) { const through = r.by ? (() => { const byEntity = getRef(r.by); return byEntity ? `, through=${byEntity.name}` : ""; })() : ""; return `${r.name} = models.ManyToManyField(${tgt_name}${through})`; } else { return `${r.name} = models.ForeignKey(${tgt_name}, blank=True, null=True, on_delete=models.CASCADE, related_name="${r.name.toLowerCase()}_%(class)s")`; } } //# sourceMappingURL=model-generator.js.map