From 9a747251f68d23971d3718b7c63e111eacdfb045 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Thu, 1 Oct 2020 10:31:43 +0200 Subject: [PATCH] add support for relational fields --- api/src/services/specifications.ts | 83 +++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/api/src/services/specifications.ts b/api/src/services/specifications.ts index ca6ec03f72..205f876f0a 100644 --- a/api/src/services/specifications.ts +++ b/api/src/services/specifications.ts @@ -85,10 +85,10 @@ const fieldTypes = { type: 'string' } } - - } +type RelationTree = Record> + export class SpecificationService { accountability: Accountability | null; fieldsService: FieldsService | null; @@ -126,6 +126,19 @@ export class SpecificationService { if(relations === undefined || relations === null) return {} if(Array.isArray(relations) === false) relations = [relations] + let relationsTree: RelationTree = {}; + (relations as Relation[]).forEach((relation: Relation) => { + if(relation.many_collection in relationsTree === false) relationsTree[relation.many_collection] = {}; + if(relation.one_collection in relationsTree === false) relationsTree[relation.one_collection] = {}; + + if(relation.many_field in relationsTree[relation.many_collection] === false) relationsTree[relation.many_collection][relation.many_field] = [] + if(relation.one_field in relationsTree[relation.one_collection] === false) relationsTree[relation.one_collection][relation.one_field] = [] + + relationsTree[relation.many_collection][relation.many_field].push(relation) + relationsTree[relation.one_collection][relation.one_field].push(relation) + }) + + const dynOpenapi = { openapi: '3.0.1', info: { @@ -136,7 +149,7 @@ export class SpecificationService { tags: this.generateTags(collections), paths: this.generatePaths(collections), components: { - schemas: this.generateSchemas(collections, fields, relations as Relation[]) + schemas: this.generateSchemas(collections, fields, relationsTree) } } @@ -289,15 +302,16 @@ export class SpecificationService { return paths } - generateSchemas(collections: Collection[], fields: Record, relations: Relation[]) { + generateSchemas(collections: Collection[], fields: Record, relations: RelationTree) { const schemas: Record = {} - for(const collection of collections) { - const isInternal = collection.collection.startsWith('directus_') + const getSchemaName = function(collection: string) { + const name = collection.startsWith('directus_') ? collection.replace('directus_','').replace(/s$/,'') : collection+"Item" + return formatTitle(name).replace(/ /g,'') + } - let name = collection.collection - name = isInternal ? name.replace('directus_','').replace(/s$/,'') : name+"Item" - name = formatTitle(name).replace(/ /g,'') + for(const collection of collections) { + let name = getSchemaName(collection.collection) const tag = formatTitle(collection.collection.replace('directus_','')) if(fields === undefined) return @@ -305,31 +319,52 @@ export class SpecificationService { schemas[name] = { type: 'object', 'x-tag': tag, - properties: {}, - relations + properties: {} } for(const field of fields[collection.collection]) { - const fieldRelations = relations.filter(relation => - (relation.many_collection === collection.collection && relation.many_field === field.field) || - (relation.one_collection === collection.collection && relation.one_field === field.field) - ) + const fieldRelations = field.collection in relations && field.field in relations[field.collection] ? relations[field.collection][field.field] : [] if(fieldRelations.length !== 0) { + const relation = fieldRelations[0] + const isManySide = relation.many_collection === field.collection + + let relatedCollection = isManySide ? relation.one_collection : relation.many_collection + const relatedPrimaryField = fields[relatedCollection].find(field => field.schema?.is_primary_key) + + if(relatedPrimaryField?.type === undefined) return; + + const relatedType = fieldTypes[relatedPrimaryField?.type] + + const relatedSchema = getSchemaName(relatedCollection) + + const type = isManySide ? { + oneOf: [{ + ...relatedType, + nullable: field.schema?.is_nullable === true, + }, {$ref: `#/components/schemas/${relatedSchema}`}] + } : { + type: 'array', + items: {$ref: `#/components/schemas/${relatedSchema}`}, + nullable: field.schema?.is_nullable === true + } + + schemas[name].properties[field.field] = { + ...type, + description: field.meta?.note || undefined + + } + } else { - + schemas[name].properties[field.field] = { + ...fieldTypes[field.type], + nullable: field.schema?.is_nullable === true, + description: field.meta?.note || undefined + } } - schemas[name].properties[field.field] = { - ...fieldTypes[field.type], - nullable: field.schema?.is_nullable === true, - description: field.meta?.note || undefined - - } - } } - return schemas } }