Skip to content

Commit

Permalink
Merge branch 'v3.5' of https://github.com/samchon/nestia into feature…
Browse files Browse the repository at this point in the history
…s/optional-query
  • Loading branch information
samchon committed Jul 8, 2024
2 parents 0bbe822 + 961de1f commit 177ce88
Show file tree
Hide file tree
Showing 48 changed files with 593 additions and 4 deletions.
14 changes: 14 additions & 0 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"name": "@nestia/sdk",
<<<<<<< HEAD
"version": "3.5.0-dev.20240707",
=======
"version": "3.5.0-dev.20240706",
>>>>>>> 961de1f1aeae07cc59cf24e43774df2bc53db2bc
"description": "Nestia SDK and Swagger generator",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
Expand Down Expand Up @@ -32,8 +36,13 @@
},
"homepage": "https://nestia.io",
"dependencies": {
<<<<<<< HEAD
"@nestia/fetcher": "^3.5.0-dev.20240707",
"@nestia/core": "^3.5.0-dev.20240707",
=======
"@nestia/fetcher": "^3.5.0-dev.20240706",
"@nestia/core": "^3.5.0-dev.20240706",
>>>>>>> 961de1f1aeae07cc59cf24e43774df2bc53db2bc
"@samchon/openapi": "^0.3.0",
"cli": "^1.0.1",
"get-function-location": "^2.0.0",
Expand All @@ -47,8 +56,13 @@
"typia": "^6.4.2"
},
"peerDependencies": {
<<<<<<< HEAD
"@nestia/fetcher": ">=3.5.0-dev.20240707",
"@nestia/core": ">=3.5.0-dev.20240707",
=======
"@nestia/fetcher": ">=3.5.0-dev.20240706",
"@nestia/core": ">=3.5.0-dev.20240706",
>>>>>>> 961de1f1aeae07cc59cf24e43774df2bc53db2bc
"@nestjs/common": ">=7.0.1",
"@nestjs/core": ">=7.0.1",
"reflect-metadata": ">=0.1.12",
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/src/INestiaConfig.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { INestApplication } from "@nestjs/common";
import type { OpenApi } from "@samchon/openapi";
import { OpenApi } from "@samchon/openapi";

/**
* Definition for the `nestia.config.ts` file.
Expand Down Expand Up @@ -239,7 +239,7 @@ export namespace INestiaConfig {
* `false`, the query DTO would be one object type which contains all of query
* parameters.
*
* @default false
* @default true
*/
decompose?: boolean;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ export namespace SwaggerSchemaGenerator {
);
return [decoded];
} else if (
props.config.decompose !== true ||
props.config.decompose === false ||
result.data.objects.length === 0
)
return [decoded];
Expand Down
16 changes: 16 additions & 0 deletions test/features/query-decompose-false/nestia.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { INestiaConfig } from "@nestia/sdk";

export const NESTIA_CONFIG: INestiaConfig = {
input: ["src/controllers"],
output: "src/api",
swagger: {
output: "swagger.json",
decompose: false,
security: {
bearer: {
type: "apiKey",
},
},
},
};
export default NESTIA_CONFIG;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { TestValidator } from "@nestia/e2e";

export const test_swagger = async () => {
const content = await import("../../../swagger.json");
TestValidator.equals("query")({
name: "query",
in: "query",
schema: { $ref: "#/components/schemas/IQuery" },
required: true,
})(
content.paths["/query/typed"].get.parameters.find((p) => p.in === "query")!,
);
};
1 change: 1 addition & 0 deletions test/features/query-decompose-false/swagger.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"openapi":"3.1.0","servers":[{"url":"https://github.com/samchon/nestia","description":"insert your server url"}],"info":{"version":"3.5.0-dev.20240706","title":"@nestia/test","description":"Test program of Nestia","license":{"name":"MIT"}},"paths":{"/query/typed":{"get":{"tags":[],"parameters":[{"name":"query","in":"query","schema":{"$ref":"#/components/schemas/IQuery"},"description":"","required":true}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IQuery"}}}}}}},"/query/nest":{"get":{"tags":[],"parameters":[{"name":"query","in":"query","schema":{"$ref":"#/components/schemas/INestQuery"},"description":"","required":true}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IQuery"}}}}}}},"/query/individual":{"get":{"tags":[],"parameters":[{"name":"id","in":"query","schema":{"type":"string"},"description":"","required":true}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"string"}}}}}}},"/query/composite":{"get":{"tags":[],"parameters":[{"name":"atomic","in":"query","schema":{"type":"string"},"description":"","required":true},{"name":"query","in":"query","schema":{"$ref":"#/components/schemas/OmitIQueryatomic"},"description":"","required":true}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IQuery"}}}}}}}},"components":{"schemas":{"IQuery":{"type":"object","properties":{"limit":{"type":"number"},"enforce":{"type":"boolean"},"values":{"type":"array","items":{"type":"string"}},"atomic":{"oneOf":[{"type":"null"},{"type":"string"}]}},"required":["enforce","values","atomic"]},"INestQuery":{"type":"object","properties":{"limit":{"type":"string","pattern":"^([+-]?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)$"},"enforce":{"oneOf":[{"const":"false"},{"const":"true"}]},"atomic":{"type":"string"},"values":{"type":"array","items":{"type":"string"}}},"required":["enforce","atomic","values"]},"OmitIQueryatomic":{"type":"object","properties":{"limit":{"type":"number"},"enforce":{"type":"boolean"},"values":{"type":"array","items":{"type":"string"}}},"required":["enforce","values"],"description":"Construct a type with the properties of T except for those in type K."}},"securitySchemes":{"bearer":{"type":"apiKey","in":"header","name":"Authorization"}}},"tags":[],"x-samchon-emended":true}
File renamed without changes.
27 changes: 27 additions & 0 deletions test/features/query-decompose-true/src/Backend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import core from "@nestia/core";
import { INestApplication } from "@nestjs/common";
import { NestFactory } from "@nestjs/core";

export class Backend {
private application_?: INestApplication;

public async open(): Promise<void> {
this.application_ = await NestFactory.create(
await core.EncryptedModule.dynamic(__dirname + "/controllers", {
key: "A".repeat(32),
iv: "B".repeat(16),
}),
{ logger: false },
);
await this.application_.listen(37_000);
}

public async close(): Promise<void> {
if (this.application_ === undefined) return;

const app = this.application_;
await app.close();

delete this.application_;
}
}
1 change: 1 addition & 0 deletions test/features/query-decompose-true/src/api/HttpError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { HttpError } from "@nestia/fetcher";
1 change: 1 addition & 0 deletions test/features/query-decompose-true/src/api/IConnection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { IConnection } from "@nestia/fetcher";
1 change: 1 addition & 0 deletions test/features/query-decompose-true/src/api/Primitive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { Primitive } from "@nestia/fetcher";
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @packageDocumentation
* @module api.functional
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
//================================================================
export * as query from "./query";
192 changes: 192 additions & 0 deletions test/features/query-decompose-true/src/api/functional/query/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/**
* @packageDocumentation
* @module api.functional.query
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
//================================================================
import type { IConnection, Resolved, Primitive } from "@nestia/fetcher";
import { PlainFetcher } from "@nestia/fetcher/lib/PlainFetcher";

import type { INestQuery } from "../../structures/INestQuery";
import type { IQuery } from "../../structures/IQuery";

/**
* @controller QueryController.typed
* @path GET /query/typed
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
export async function typed(
connection: IConnection,
query: typed.Query,
): Promise<typed.Output> {
return PlainFetcher.fetch(connection, {
...typed.METADATA,
template: typed.METADATA.path,
path: typed.path(query),
});
}
export namespace typed {
export type Query = Resolved<IQuery>;
export type Output = Primitive<IQuery>;

export const METADATA = {
method: "GET",
path: "/query/typed",
request: null,
response: {
type: "application/json",
encrypted: false,
},
status: null,
} as const;

export const path = (query: typed.Query) => {
const variables: URLSearchParams = new URLSearchParams();
for (const [key, value] of Object.entries(query as any))
if (undefined === value) continue;
else if (Array.isArray(value))
value.forEach((elem: any) => variables.append(key, String(elem)));
else variables.set(key, String(value));
const location: string = "/query/typed";
return 0 === variables.size
? location
: `${location}?${variables.toString()}`;
};
}

/**
* @controller QueryController.nest
* @path GET /query/nest
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
export async function nest(
connection: IConnection,
query: nest.Query,
): Promise<nest.Output> {
return PlainFetcher.fetch(connection, {
...nest.METADATA,
template: nest.METADATA.path,
path: nest.path(query),
});
}
export namespace nest {
export type Query = Resolved<INestQuery>;
export type Output = Primitive<IQuery>;

export const METADATA = {
method: "GET",
path: "/query/nest",
request: null,
response: {
type: "application/json",
encrypted: false,
},
status: null,
} as const;

export const path = (query: nest.Query) => {
const variables: URLSearchParams = new URLSearchParams();
for (const [key, value] of Object.entries(query as any))
if (undefined === value) continue;
else if (Array.isArray(value))
value.forEach((elem: any) => variables.append(key, String(elem)));
else variables.set(key, String(value));
const location: string = "/query/nest";
return 0 === variables.size
? location
: `${location}?${variables.toString()}`;
};
}

/**
* @controller QueryController.individual
* @path GET /query/individual
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
export async function individual(
connection: IConnection,
id: string,
): Promise<individual.Output> {
return PlainFetcher.fetch(connection, {
...individual.METADATA,
template: individual.METADATA.path,
path: individual.path(id),
});
}
export namespace individual {
export type Output = Primitive<string>;

export const METADATA = {
method: "GET",
path: "/query/individual",
request: null,
response: {
type: "application/json",
encrypted: false,
},
status: null,
} as const;

export const path = (id: string) => {
const variables: URLSearchParams = new URLSearchParams();
for (const [key, value] of Object.entries({
id,
} as any))
if (undefined === value) continue;
else if (Array.isArray(value))
value.forEach((elem: any) => variables.append(key, String(elem)));
else variables.set(key, String(value));
const location: string = "/query/individual";
return 0 === variables.size
? location
: `${location}?${variables.toString()}`;
};
}

/**
* @controller QueryController.composite
* @path GET /query/composite
* @nestia Generated by Nestia - https://github.com/samchon/nestia
*/
export async function composite(
connection: IConnection,
atomic: string,
query: composite.Query,
): Promise<composite.Output> {
return PlainFetcher.fetch(connection, {
...composite.METADATA,
template: composite.METADATA.path,
path: composite.path(atomic, query),
});
}
export namespace composite {
export type Query = Resolved<Omit<IQuery, "atomic">>;
export type Output = Primitive<IQuery>;

export const METADATA = {
method: "GET",
path: "/query/composite",
request: null,
response: {
type: "application/json",
encrypted: false,
},
status: null,
} as const;

export const path = (atomic: string, query: composite.Query) => {
const variables: URLSearchParams = new URLSearchParams();
for (const [key, value] of Object.entries({
...query,
atomic,
} as any))
if (undefined === value) continue;
else if (Array.isArray(value))
value.forEach((elem: any) => variables.append(key, String(elem)));
else variables.set(key, String(value));
const location: string = "/query/composite";
return 0 === variables.size
? location
: `${location}?${variables.toString()}`;
};
}
4 changes: 4 additions & 0 deletions test/features/query-decompose-true/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import * as api from "./module";

export * from "./module";
export default api;
5 changes: 5 additions & 0 deletions test/features/query-decompose-true/src/api/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type * from "./IConnection";
export type * from "./Primitive";
export * from "./HttpError";

export * as functional from "./functional";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface INestQuery {
limit?: `${number}`;
enforce: `${boolean}`;
atomic: string;
values: string[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface IQuery {
limit?: number;
enforce: boolean;
values: string[];
atomic: string | null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { TypedQuery, TypedRoute } from "@nestia/core";
import { Controller, Query } from "@nestjs/common";

import { INestQuery } from "@api/lib/structures/INestQuery";
import { IQuery } from "@api/lib/structures/IQuery";

@Controller("query")
export class QueryController {
@TypedRoute.Get("typed")
public async typed(@TypedQuery() query: IQuery): Promise<IQuery> {
return query;
}

@TypedRoute.Get("nest")
public async nest(@Query() query: INestQuery): Promise<IQuery> {
return {
limit: query.limit !== undefined ? Number(query.limit) : undefined,
enforce: query.enforce === "true",
atomic: query.atomic === "null" ? null : query.atomic,
values: query.values,
};
}

@TypedRoute.Get("individual")
public async individual(@Query("id") id: string): Promise<string> {
return id;
}

@TypedRoute.Get("composite")
public async composite(
@Query("atomic") atomic: string,
@TypedQuery() query: Omit<IQuery, "atomic">,
): Promise<IQuery> {
return {
...query,
atomic,
};
}
}
Loading

0 comments on commit 177ce88

Please sign in to comment.