Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/generator/01-base/static/queriesWithFilter.ts.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export type CountQuery<F> = {

export type SomeQuery<E, F, I, P> = {
serializeNulls?: boolean;
include?: QuerySelect<I>;
include?: I;
properties?: P;
filter?: QueryFilter<F> & CustomAttributeFilter;
select?: QuerySelect<E>;
Expand Down Expand Up @@ -178,7 +178,7 @@ const _some = (
includeReferencedEntities: query?.include
? usePost
? Object.keys(query.include)
: Object.keys(query.include).join(',')
: flattenIncludedReferences(query.include).join(',')
: undefined,
...flattenOrFilter(query?.or),
...flattenFilter(query?.filter),
Expand Down
4 changes: 2 additions & 2 deletions src/generator/01-base/static/queriesWithQueryLanguage.ts.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export type CountQuery<F> = {

type SomeQueryBase<E, F, I, P> = {
serializeNulls?: boolean;
include?: QuerySelect<I>;
include?: I;
properties?: P;
where?: QueryFilter<F>;
select?: QuerySelect<E>;
Expand Down Expand Up @@ -387,7 +387,7 @@ const _some = (
includeReferencedEntities: query?.include
? usePost
? Object.keys(query.include)
: Object.keys(query.include).join(',')
: flattenIncludedReferences(query.include).join(',')
: undefined,
...assembleFilterParam(query?.where),
...flattenSort(query?.sort, usePost),
Expand Down
4 changes: 2 additions & 2 deletions src/generator/01-base/static/types.ts.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ export type UniqueQuery = {
serializeNulls?: boolean;
};

export type SomeQueryReturn<E, R, P> = {
export type SomeQueryReturn<E, P> = {
entities: E[];
references?: R;
references?: ReferencedEntities;
properties?: P[];
};

Expand Down
16 changes: 16 additions & 0 deletions src/generator/01-base/static/utils.ts.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@ const flattenSelect = (obj: Select<any, any> = {}): string[] => {
return entries;
};

const flattenIncludedReferences = (obj: Record<any, any> = {}, base = ''): string[] => {
const entries: string[] = [];

for (const [prop, value] of Object.entries(obj)) {
const path = base ? `${base}.${prop}` : prop;

if (typeof value === 'object' && value) {
entries.push(...flattenIncludedReferences(value as Record<any, any>, path));
} else if (value) {
entries.push(path);
}
}

return entries;
};

export const flattenSort = (obj: Sort<any>[] = [], usePost?: boolean):
{ sort?: string } | { orderBy?: string[] } | Record<string, never> => {
const flatten = (obj: Sort<any>, base = ''): string | undefined => {
Expand Down
33 changes: 30 additions & 3 deletions src/generator/03-entities/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { extractPropertyMetaData, PropertyMetaData } from '@generator/03-entities/utils/extractPropertyMetaData';
import { generateInterface, InterfaceProperty } from '@ts/generateInterface';
import { logger } from '@logger';
import { generateInterface, generateInterfaceType, InterfaceProperty } from '@ts/generateInterface';
import { generateStatements } from '@ts/generateStatements';
import { loosePascalCase } from '@utils/case';
import { convertToTypeScriptType, createReferenceType, getRefName } from '@utils/openapi/convertToTypeScriptType';
import { ExtendedSchema, isEnumSchemaObject, isReferenceObject } from '@utils/openapi/guards';
import { OpenAPIV3 } from 'openapi-types';
import { logger } from '@logger';
import { OpenApiContext } from '@utils/weclapp/extractContext';
import { OpenAPIV3 } from 'openapi-types';

export interface GeneratedEntity {
name: string;
Expand Down Expand Up @@ -144,3 +144,30 @@ export const generateEntities = (context: OpenApiContext): Map<string, Generated

return entities;
};

export const generateReferencedEntities = (
entities: Map<string, GeneratedEntity>,
aliases: Map<string, string>,
services: Map<string, { name: string }>
) => {
const aliasKeys = new Set(aliases.keys());
const serviceKeys = new Set(services.keys());

return generateInterfaceType(
'ReferencedEntities',
[
...[...entities.values()]
.filter((entity) => aliasKeys.has(entity.name) && serviceKeys.has(entity.name))
.map((entity) => ({
name: entity.name,
type: `${entity.interfaceName}[]`
})),
...[...aliases.entries()]
.filter(([, alias]) => alias === 'customValue')
.map(([entityName]) => ({
name: entityName,
type: 'CustomValue[]'
}))
].sort((a, b) => a.name.localeCompare(b.name))
);
};
115 changes: 81 additions & 34 deletions src/generator/04-services/endpoints/some.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { GeneratedServiceFunction, ServiceFunctionGenerator } from '@generator/0
import { generateArrowFunction } from '@ts/generateArrowFunction';
import { generateArrowFunctionType } from '@ts/generateArrowFunctionType';
import { generateInterfaceFromObject, generateInterfaceType, InterfaceProperty } from '@ts/generateInterface';
import { generateObject, ObjectProperty } from '@ts/generateObject';
import { generateString } from '@ts/generateString';
import { generateTupleArray } from '@ts/generateTupleArray';
import { generateType } from '@ts/generateType';
Expand Down Expand Up @@ -46,46 +47,99 @@ const resolveAdditionalPropertiesSchema = (
return undefined;
};

const resolveReferences = (entity: string, entities: Map<string, GeneratedEntity>) => {
const references: InterfaceProperty[] = [];
const resolveArrayReferenceProperties = (
entity: string,
entities: Map<string, GeneratedEntity>,
visitedEntities = new Set<string>()
): ObjectProperty[] => {
if (!entity || visitedEntities.has(entity)) {
return [];
}

const generatedEntity = entities.get(entity);
if (generatedEntity) {
for (const [property, propertyMetaData] of generatedEntity.properties) {
if (propertyMetaData.service) {
references.push({
name: property,
type: generateString(propertyMetaData.service),
required: true
});
if (!generatedEntity) {
return [];
}

const nextVisitedEntities = new Set(visitedEntities);
nextVisitedEntities.add(entity);

const properties: ObjectProperty[] = [...generatedEntity.properties.entries()].flatMap(
([property, propertyMetaData]): ObjectProperty[] => {
if (propertyMetaData.type === 'array') {
if (propertyMetaData.entity === 'onlyId') {
return [{ key: property, value: [{ key: 'id', value: 'boolean' }] }];
}

if (!propertyMetaData.entity) {
return [];
}

const nestedProperties = resolveArrayReferenceProperties(
propertyMetaData.entity,
entities,
nextVisitedEntities
);

if (!nestedProperties.length) {
return [];
}

return [{ key: property, value: nestedProperties }];
}

if (property.endsWith('Id')) {
return [{ key: property, value: 'boolean' }];
}

return [];
}
if (generatedEntity.parentName) {
references.push(...resolveReferences(generatedEntity.parentName, entities));
}
);

if (generatedEntity.parentName) {
properties.push(...resolveArrayReferenceProperties(generatedEntity.parentName, entities, nextVisitedEntities));
}
return references;

return properties;
};

const resolveReferencedEntities = (entity: string, entities: Map<string, GeneratedEntity>) => {
const referencedEntities: InterfaceProperty[] = [];
const resolveReferences = (entity: string, entities: Map<string, GeneratedEntity>) => {
const references: InterfaceProperty[] = [];
const generatedEntity = entities.get(entity);
if (generatedEntity) {
for (const [, propertyMetaData] of generatedEntity.properties) {
if (propertyMetaData.service && propertyMetaData.entity) {
const referencedEntity = entities.get(propertyMetaData.entity);
if (referencedEntity)
referencedEntities.push({
name: propertyMetaData.service,
type: `${referencedEntity.interfaceName}[]`,
required: true
for (const [property, propertyMetaData] of generatedEntity.properties) {
if (property === 'customAttributes') continue;

if (propertyMetaData.type === 'array') {
if (propertyMetaData.entity === 'onlyId') {
references.push({
name: property,
type: generateObject([{ key: 'id', value: 'boolean' }])
});
} else {
const nestedProperties = resolveArrayReferenceProperties(propertyMetaData.entity || '', entities);
if (nestedProperties.length) {
references.push({
name: property,
type: generateObject(nestedProperties)
});
}
}
} else {
if (propertyMetaData.service) {
references.push({
name: property,
type: 'boolean'
});
}
}
}
if (generatedEntity.parentName) {
referencedEntities.push(...resolveReferencedEntities(generatedEntity.parentName, entities));
references.push(...resolveReferences(generatedEntity.parentName, entities));
}
}
return referencedEntities;

return references;
};

export const generateSomeEndpoint: ServiceFunctionGenerator = ({
Expand Down Expand Up @@ -134,12 +188,6 @@ export const generateSomeEndpoint: ServiceFunctionGenerator = ({
`SomeQuery<${relatedEntity.interfaceName}, ${filterTypeName}, ${referencesTypeName}, ${additionalPropertyTypeName}> & ${parametersTypeName}`
);

const referencedEntitiesTypeName = `${functionTypeName}_ReferencedEntities`;
const referencedEntitiesTypeSource = generateInterfaceType(
referencedEntitiesTypeName,
resolveReferencedEntities(endpoint.service, entities)
);

const additionalPropertiesTypeName = `${functionTypeName}_AdditionalProperties`;

const additionalPropertiesTypeSource = generateType(
Expand All @@ -150,7 +198,7 @@ export const generateSomeEndpoint: ServiceFunctionGenerator = ({
const functionTypeSource = generateArrowFunctionType({
type: functionTypeName,
params: [`query${parametersType.isFullyOptional() ? '?' : ''}: ${queryTypeName}, requestOptions?: RequestOptions`],
returns: `${resolveResponseType(options.target)}<SomeQueryReturn<${relatedEntity.interfaceName}, ${referencedEntitiesTypeName}, ${additionalPropertiesTypeName}>>`
returns: `${resolveResponseType(options.target)}<SomeQueryReturn<${relatedEntity.interfaceName}, ${additionalPropertiesTypeName}>>`
});

const functionSource = generateArrowFunction({
Expand All @@ -170,7 +218,6 @@ export const generateSomeEndpoint: ServiceFunctionGenerator = ({
{ name: referencesTypeName, source: referencesTypeSource },
{ name: additionalPropertyTypeName, source: additionalPropertyTypeSource },
{ name: queryTypeName, source: queryTypeSource },
{ name: referencedEntitiesTypeName, source: referencedEntitiesTypeSource },
{ name: additionalPropertiesTypeName, source: additionalPropertiesTypeSource }
]
};
Expand Down
5 changes: 3 additions & 2 deletions src/generator/generate.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Target } from '../target';
import { generateBase } from '@generator/01-base';
import { generateEnums } from '@generator/02-enums';
import { generateEntities } from '@generator/03-entities';
import { generateEntities, generateReferencedEntities } from '@generator/03-entities';
import { generateServices } from '@generator/04-services';
import { generateMaps } from '@generator/05-maps';
import { generateBlockComment } from '@ts/generateComment';
import { generateStatements } from '@ts/generateStatements';
import { extractContext } from '@utils/weclapp/extractContext';
import { OpenAPIV3 } from 'openapi-types';
import { Target } from '../target';

export interface GeneratorOptions {
/* Generate unique methods as well. */
Expand All @@ -34,6 +34,7 @@ export const generate = (doc: OpenAPIV3.Document, options: GeneratorOptions): st
generateBlockComment('ENUMS', generateStatements(...[...enums.values()].map((v) => v.source))),
generateBlockComment('ENTITIES', generateStatements(...[...entities.values()].map((v) => v.source))),
generateBlockComment('FILTERS', generateStatements(...[...entities.values()].map((v) => v.filterSource))),
generateBlockComment('REFERENCED ENTITIES', generateReferencedEntities(entities, context.aliases, services)),
generateBlockComment('SERVICES', generateStatements(...[...services.values()].map((v) => v.source))),
generateBlockComment('MAPS', maps)
);
Expand Down
Loading