Skip to content

Commit b389652

Browse files
committed
feat: split swagger content to a separate table and return it on demand
1 parent b00c148 commit b389652

File tree

15 files changed

+274
-106
lines changed

15 files changed

+274
-106
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"start:dev": "npx nodemon"
99
},
1010
"devDependencies": {
11-
"@koa/router": "^12.0.0",
1211
"@types/js-yaml": "^4.0.5",
1312
"@types/koa": "^2.13.8",
1413
"@types/koa__router": "^12.0.0",
@@ -32,6 +31,7 @@
3231
"prettier": "^2.8.8"
3332
},
3433
"dependencies": {
34+
"@koa/router": "^12.0.0",
3535
"dotenv": "^10.0.0",
3636
"http-status-codes": "^2.2.0",
3737
"js-yaml": "^4.1.0",
@@ -56,4 +56,4 @@
5656
},
5757
"author": "",
5858
"license": "ISC"
59-
}
59+
}

src/helpers/common.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ export const Headers = {
33
};
44

55
export const ErrorMessages = {
6-
SWAGGER_NOT_PARSABLE: 'Could not parse swagger data',
6+
SWAGGER_NOT_PARSABLE: 'Could not parse swagger file content',
77
SWAGGER_NAME_ALREADY_EXISTS: 'Swagger with the same name already exists',
8-
SWAGGER_TITLE_ALREADY_EXISTS: 'Swagger with the same title already exists',
98
SWAGGER_NOT_FOUND: 'Swagger not found',
109
};

src/helpers/env.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ const env: Env = {
3333
SQLITE_STORAGE_PATH:
3434
process.env.SQLITE_STORAGE_PATH || './db/swaggipedia.sqlite',
3535
PORT: Number(process.env.PORT) || 3000,
36-
FORCE_SHUTDOWN_TIMEOUT_SEC: Number(process.env.FORCE_SHUTDOWN_TIMEOUT_SEC),
37-
SHUTDOWN_INITIAL_DELAY_SEC: Number(process.env.SHUTDOWN_INITIAL_DELAY_SEC),
36+
FORCE_SHUTDOWN_TIMEOUT_SEC:
37+
Number(process.env.FORCE_SHUTDOWN_TIMEOUT_SEC) || 30,
38+
SHUTDOWN_INITIAL_DELAY_SEC:
39+
Number(process.env.SHUTDOWN_INITIAL_DELAY_SEC) || 5,
3840
SERVER_KEEP_ALIVE: Number(process.env.SERVER_KEEP_ALIVE),
3941
};
4042

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export const TableNames = {
22
SWAGGERS_TABLE_NAME: 'swaggers',
3+
SWAGGERS_CONTENT_TABLE_NAME: 'swaggers_content',
34
};

src/server/database/connectors/sequlize/migrations/00_initial.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
import { DataTypes } from 'sequelize';
22
import { TableNames } from '../../consts';
33

4-
export const up = async ({ context }) =>
4+
export const up = async ({ context }) => {
5+
await context.createTable(TableNames.SWAGGERS_CONTENT_TABLE_NAME, {
6+
id: {
7+
type: DataTypes.UUID,
8+
primaryKey: true,
9+
},
10+
file_content: {
11+
type: DataTypes.TEXT('long'),
12+
allowNull: false,
13+
},
14+
});
515
await context.createTable(TableNames.SWAGGERS_TABLE_NAME, {
616
id: {
717
type: DataTypes.UUID,
@@ -12,9 +22,13 @@ export const up = async ({ context }) =>
1222
type: DataTypes.STRING,
1323
allowNull: false,
1424
},
15-
data: {
16-
type: DataTypes.TEXT('long'),
25+
file_content_id: {
26+
type: DataTypes.UUID,
1727
allowNull: false,
28+
references: {
29+
model: TableNames.SWAGGERS_CONTENT_TABLE_NAME,
30+
key: 'id',
31+
},
1832
},
1933
created_at: {
2034
type: DataTypes.DATE,
@@ -25,6 +39,7 @@ export const up = async ({ context }) =>
2539
allowNull: false,
2640
},
2741
});
42+
};
2843

2944
export const down = async ({ context: queryInterface }) =>
3045
await queryInterface.dropTable(TableNames.SWAGGERS_TABLE_NAME);

src/server/database/models/swagger.ts

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,67 @@
11
import { v4 } from 'uuid';
2-
import { DataTypes, Model, Optional, Sequelize } from 'sequelize';
2+
import { DataTypes, Model, ModelStatic, Sequelize } from 'sequelize';
33
import { TableNames } from '../connectors/consts';
44

55
export enum SwaggerFormats {
66
Yaml = 'yaml',
77
Json = 'json',
88
}
99

10-
interface SwaggerAttributes {
10+
export interface SwaggerFileContent {
11+
id: string;
12+
file_content: string;
13+
}
14+
15+
export interface InternalSwaggerResource {
1116
id: string;
1217
name: string;
13-
data: string;
18+
file_content_id?: string;
19+
FileContent?: SwaggerFileContent;
1420
created_at?: Date;
1521
updated_at?: Date;
1622
}
17-
export type SwaggerRequestBody = Optional<
18-
SwaggerAttributes,
19-
'id' | 'created_at' | 'updated_at'
20-
>;
21-
export type SwaggerResource = Required<SwaggerAttributes>;
23+
export type SwaggerRequestBody = {
24+
name: string;
25+
file_content: string;
26+
};
27+
export type SwaggerResource = Omit<
28+
InternalSwaggerResource,
29+
'file_content_id'
30+
> & {
31+
file_content?: string;
32+
};
2233

2334
class SwaggerModel
24-
extends Model<SwaggerAttributes, SwaggerRequestBody>
25-
implements SwaggerAttributes
35+
extends Model<InternalSwaggerResource, SwaggerRequestBody>
36+
implements InternalSwaggerResource
2637
{
38+
public static FileContent: ModelStatic<Model<SwaggerFileContent>>;
39+
2740
public id!: string;
2841
public name!: string;
29-
public data!: string;
42+
public readonly file_content_id!: string;
3043
public readonly created_at!: Date;
3144
public readonly updated_at!: Date;
3245

3346
public static initializeModel(sequelizeClient: Sequelize): void {
47+
this.FileContent = sequelizeClient.define(
48+
'FileContent',
49+
{
50+
id: {
51+
type: DataTypes.UUID,
52+
primaryKey: true,
53+
},
54+
file_content: {
55+
type: DataTypes.TEXT('long'),
56+
allowNull: false,
57+
},
58+
},
59+
{
60+
tableName: TableNames.SWAGGERS_CONTENT_TABLE_NAME,
61+
timestamps: false,
62+
}
63+
);
64+
3465
this.init(
3566
{
3667
id: {
@@ -41,27 +72,68 @@ class SwaggerModel
4172
type: DataTypes.STRING,
4273
allowNull: false,
4374
},
44-
data: {
45-
type: DataTypes.TEXT('long'),
46-
allowNull: false,
47-
},
4875
},
4976
{
5077
tableName: TableNames.SWAGGERS_TABLE_NAME,
5178
sequelize: sequelizeClient,
5279
}
5380
);
81+
82+
this.belongsTo(this.FileContent, {
83+
foreignKey: {
84+
name: 'file_content_id',
85+
allowNull: false,
86+
},
87+
});
5488
}
5589

5690
public static fromRequest(requestBody: SwaggerRequestBody): SwaggerResource {
5791
const now = new Date();
92+
5893
return {
5994
id: v4(),
60-
...requestBody,
95+
name: requestBody.name,
96+
file_content: requestBody.file_content,
6197
created_at: now,
6298
updated_at: now,
6399
};
64100
}
101+
102+
public static toResponse(swagger: SwaggerModel): SwaggerResource {
103+
const { file_content_id, FileContent, ...restSwaggerProps } =
104+
swagger.dataValues;
105+
106+
if (FileContent) {
107+
return this.toResponseWithFileContent(restSwaggerProps, FileContent);
108+
}
109+
110+
return restSwaggerProps;
111+
}
112+
113+
private static toResponseWithFileContent(
114+
swagger: SwaggerResource,
115+
swaggerFileContent: SwaggerFileContent
116+
): SwaggerResource {
117+
return {
118+
id: swagger.id,
119+
name: swagger.name,
120+
file_content: swaggerFileContent.file_content,
121+
created_at: swagger.created_at,
122+
updated_at: swagger.updated_at,
123+
};
124+
}
125+
126+
public static async includeFileContent(
127+
swagger: SwaggerModel
128+
): Promise<SwaggerResource> {
129+
const fileContent = (await swagger[
130+
'getFileContent'
131+
]()) as SwaggerFileContent;
132+
133+
const { file_content_id, ...restSwaggerProps } = swagger.dataValues;
134+
135+
return this.toResponseWithFileContent(restSwaggerProps, fileContent);
136+
}
65137
}
66138

67139
export default SwaggerModel;
Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,72 @@
1+
import { v4 } from 'uuid';
12
import SwaggerModel, {
23
SwaggerRequestBody,
4+
InternalSwaggerResource,
35
SwaggerResource,
46
} from '../models/swagger';
57

68
export class SwaggersRepository {
7-
public static async getAllSwaggers(): Promise<SwaggerResource[]> {
8-
const swaggers = await SwaggerModel.findAll();
9+
public static async getAllSwaggers(
10+
includeFileContent = false
11+
): Promise<SwaggerModel[]> {
12+
const swaggers = await SwaggerModel.findAll({
13+
include: includeFileContent ? SwaggerModel.FileContent : undefined,
14+
});
15+
916
return swaggers;
1017
}
11-
public static async getSwagger(id: string): Promise<SwaggerResource> {
18+
public static async getSwagger(id: string): Promise<SwaggerModel> {
1219
const swaggers = await SwaggerModel.findByPk(id);
1320
return swaggers;
1421
}
1522

1623
public static async createSwagger(
1724
swagger: SwaggerResource
1825
): Promise<SwaggerResource> {
19-
const createdSwagger = await SwaggerModel.create(swagger);
20-
return createdSwagger;
26+
const { file_content, ...restSwaggerProps } = swagger;
27+
const swaggerFileContent = {
28+
id: v4(),
29+
file_content: file_content,
30+
};
31+
32+
await SwaggerModel.FileContent.create(swaggerFileContent);
33+
await SwaggerModel.create({
34+
...restSwaggerProps,
35+
file_content_id: swaggerFileContent.id,
36+
} as InternalSwaggerResource);
37+
38+
return swagger;
2139
}
2240

2341
public static async updateSwagger(
2442
existingResource: SwaggerModel,
2543
payload: SwaggerRequestBody
26-
): Promise<SwaggerResource> {
27-
const updatedSwagger = await existingResource.update({
28-
...payload,
29-
updated_at: new Date(),
30-
});
44+
): Promise<void> {
45+
if (payload.name) {
46+
await existingResource.update({
47+
name: payload.name,
48+
updated_at: new Date(),
49+
});
50+
}
3151

32-
return updatedSwagger;
52+
if (payload.file_content) {
53+
await SwaggerModel.FileContent.update(
54+
{
55+
file_content: payload.file_content,
56+
},
57+
{ where: { id: existingResource.file_content_id } }
58+
);
59+
}
3360
}
3461

35-
public static async deleteSwagger(id: string): Promise<boolean> {
62+
public static async deleteSwagger(swagger: SwaggerModel): Promise<boolean> {
3663
const deletedSwagger = await SwaggerModel.destroy({
37-
where: { id },
64+
where: { id: swagger.id },
3865
});
66+
SwaggerModel.FileContent.destroy({
67+
where: { id: swagger.file_content_id },
68+
});
69+
3970
return !!deletedSwagger;
4071
}
4172
}

src/server/middlewares/findSwagger.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { Context, Next } from 'koa';
22
import { StatusCodes } from 'http-status-codes';
3-
import { SwaggerResource } from '../database/models/swagger';
3+
import SwaggerModel from '../database/models/swagger';
44
import { SwaggersRepository } from '../database/repositories/swaggerRepo';
55
import { ErrorMessages } from '../../helpers/common';
66

77
declare module 'koa' {
88
interface ExtendableContext {
9-
swaggerResource?: SwaggerResource;
9+
swaggerResource?: SwaggerModel;
1010
}
1111
}
1212

0 commit comments

Comments
 (0)