pg-mvc-service 2.0.42 → 2.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/favicon.ico +0 -0
- package/dist/models/TableDoc.js +4 -1
- package/package.json +8 -2
- package/index.d.ts +0 -189
- package/src/PoolManager.ts +0 -48
- package/src/Service.ts +0 -276
- package/src/Utils/DateTimeUtil.ts +0 -146
- package/src/Utils/NumberUtil.ts +0 -23
- package/src/Utils/StringUtil.ts +0 -33
- package/src/clients/AwsS3Client.ts +0 -310
- package/src/clients/Base64Client.ts +0 -305
- package/src/clients/EncryptClient.ts +0 -100
- package/src/clients/StringClient.ts +0 -19
- package/src/cron/BaseCron.ts +0 -122
- package/src/cron/CronExecuter.ts +0 -34
- package/src/cron/CronType.ts +0 -25
- package/src/documents/Swagger.ts +0 -105
- package/src/exceptions/Exception.ts +0 -72
- package/src/index.ts +0 -23
- package/src/models/ExpressionClient.ts +0 -72
- package/src/models/MigrateDatabase.ts +0 -135
- package/src/models/MigrateRollback.ts +0 -151
- package/src/models/MigrateTable.ts +0 -56
- package/src/models/SqlUtils/SelectExpression.ts +0 -97
- package/src/models/SqlUtils/UpdateExpression.ts +0 -29
- package/src/models/SqlUtils/ValidateValueUtil.ts +0 -354
- package/src/models/SqlUtils/WhereExpression.ts +0 -421
- package/src/models/TableDoc.ts +0 -366
- package/src/models/TableModel.ts +0 -701
- package/src/models/Type.ts +0 -62
- package/src/models/Utils/MessageUtil.ts +0 -60
- package/src/models/ValidateClient.ts +0 -182
- package/src/reqestResponse/ReqResType.ts +0 -170
- package/src/reqestResponse/RequestType.ts +0 -918
- package/src/reqestResponse/ResponseType.ts +0 -420
- package/tsconfig.json +0 -14
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
export default class DateTimeUtil {
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Checks if the value is a valid date-time format
|
|
5
|
-
* 値が有効な日付時間形式かどうかを確認します
|
|
6
|
-
* @param value - 検証する値, The value to be validated
|
|
7
|
-
* @returns {boolean} - 値が有効な日付時間形式であるかどうか, Whether the value is a valid date-time format
|
|
8
|
-
*/
|
|
9
|
-
private static isErrorDateTime(value: string): boolean {
|
|
10
|
-
try {
|
|
11
|
-
const [datePart, timePart] = value.split(' ');
|
|
12
|
-
const [year, month, day] = datePart.split('-').map(Number);
|
|
13
|
-
let [hour, minute, sec] = [0, 0, 0];
|
|
14
|
-
if (timePart !== undefined) {
|
|
15
|
-
[hour, minute, sec] = timePart.split(':').map(Number);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const date = new Date(year, month - 1, day, hour, minute, sec);
|
|
19
|
-
return year !== date.getFullYear() ||
|
|
20
|
-
month !== date.getMonth() + 1 ||
|
|
21
|
-
day !== date.getDate() ||
|
|
22
|
-
hour !== date.getHours() ||
|
|
23
|
-
minute !== date.getMinutes() ||
|
|
24
|
-
sec !== date.getSeconds()
|
|
25
|
-
} catch (error) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Generates a Date object from a string.
|
|
32
|
-
* 文字列からDateオブジェクトを生成します。
|
|
33
|
-
* @param dateString A string representing the date and time (e.g., "2023-10-05 14:30:00")
|
|
34
|
-
* 日付と時間を表す文字列(例: "2023-10-05 14:30:00")
|
|
35
|
-
* @returns Date object
|
|
36
|
-
* Dateオブジェクト
|
|
37
|
-
*/
|
|
38
|
-
static toDateFromString(dateString: string): Date {
|
|
39
|
-
const [datePart, timePart] = dateString.split(' ');
|
|
40
|
-
const [year, month, day] = datePart.split('-').map(Number);
|
|
41
|
-
let [hours, minutes, seconds] = [0, 0, 0];
|
|
42
|
-
if (timePart !== undefined) {
|
|
43
|
-
[hours, minutes, seconds] = timePart.split(':').map(Number);
|
|
44
|
-
}
|
|
45
|
-
return new Date(year, month - 1, day, hours, minutes, seconds);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Formats the specified date.
|
|
50
|
-
* 指定された日付をフォーマットします。
|
|
51
|
-
* @param date The date object to be formatted.
|
|
52
|
-
* フォーマットする対象の日付オブジェクト
|
|
53
|
-
* @param type A string specifying the type of format.
|
|
54
|
-
* フォーマットの種類を指定する文字列
|
|
55
|
-
* @returns A formatted date string.
|
|
56
|
-
* フォーマットされた日付文字列
|
|
57
|
-
*/
|
|
58
|
-
static toStringFromDate(date: Date, type: 'datetime' | 'date' | 'time'): string {
|
|
59
|
-
|
|
60
|
-
const year = date.getFullYear().toString().padStart(4, '0');
|
|
61
|
-
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
62
|
-
const day = date.getDate().toString().padStart(2, '0');
|
|
63
|
-
const hour = date.getHours().toString().padStart(2, '0');
|
|
64
|
-
const minute = date.getMinutes().toString().padStart(2, '0');
|
|
65
|
-
const second = date.getSeconds().toString().padStart(2, '0');
|
|
66
|
-
|
|
67
|
-
switch (type) {
|
|
68
|
-
case 'datetime':
|
|
69
|
-
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
|
70
|
-
case 'date':
|
|
71
|
-
return `${year}-${month}-${day}`;
|
|
72
|
-
case 'time':
|
|
73
|
-
return `${hour}:${minute}:${second}`;
|
|
74
|
-
default:
|
|
75
|
-
throw new Error('Invalid type');
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Validates if the given value is in the format YYYY-MM-DD
|
|
81
|
-
* 与えられた値がYYYY-MM-DD形式であるかどうかを検証します
|
|
82
|
-
* @param value - The value to be validated, 検証する値
|
|
83
|
-
* @returns {boolean} - Whether the value is in the format YYYY-MM-DD, 値がYYYY-MM-DD形式であるかどうか
|
|
84
|
-
*/
|
|
85
|
-
static isYYYYMMDD(value: any) {
|
|
86
|
-
if (typeof value !== 'string') {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const pattern = new RegExp('^\\d{4}-\\d{2}-\\d{2}$');
|
|
91
|
-
if (pattern.test(value) === false) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return this.isErrorDateTime(value) === false;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Validates if the given value is in the format YYYY-MM-DD hh:mm:ss
|
|
100
|
-
* 与えられた値がYYYY-MM-DD hh:mm:ss形式であるかどうかを検証します
|
|
101
|
-
* @param value - The value to be validated, 検証する値
|
|
102
|
-
* @returns {boolean} - Whether the value is in the format YYYY-MM-DD hh:mm:ss, 値がYYYY-MM-DD hh:mm:ss形式であるかどうか
|
|
103
|
-
*/
|
|
104
|
-
static isYYYYMMDDhhmiss(value: any) {
|
|
105
|
-
if (typeof value !== 'string') {
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const pattern = new RegExp('^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}:\\d{2}$');
|
|
110
|
-
if (pattern.test(value) === false) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return this.isErrorDateTime(value) === false;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Validates if the given value is in the format YYYY-MM-DD hh:mm:ss
|
|
119
|
-
* 与えられた値がYYYY-MM-DD hh:mm:ss形式であるかどうかを検証します
|
|
120
|
-
* @param value - The value to be validated, 検証する値
|
|
121
|
-
* @returns {boolean} - Whether the value is in the format YYYY-MM-DD hh:mm:ss, 値がYYYY-MM-DD hh:mm:ss形式であるかどうか
|
|
122
|
-
*/
|
|
123
|
-
static isHHMM(value: any) {
|
|
124
|
-
if (typeof value !== 'string') {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const pattern = new RegExp('^(?:[01]\\d|2[0-3]):[0-5]\\d$');
|
|
129
|
-
return pattern.test(value);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Validates if the given value is in the format HH:MM:SS
|
|
134
|
-
* 与えられた値がHH:MM:SS形式であるかどうかを検証します
|
|
135
|
-
* @param value - The value to be validated, 検証する値
|
|
136
|
-
* @returns {boolean} - Whether the value is in the format HH:MM:SS, 値がHH:MM:SS形式であるかどうか
|
|
137
|
-
*/
|
|
138
|
-
static isHHMMSS(value: any) {
|
|
139
|
-
if (typeof value !== 'string') {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const pattern = new RegExp('^(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d$');
|
|
144
|
-
return pattern.test(value);
|
|
145
|
-
}
|
|
146
|
-
}
|
package/src/Utils/NumberUtil.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export default class NumberUtil {
|
|
2
|
-
/**
|
|
3
|
-
* Checks if the given value is a number.
|
|
4
|
-
* 与えられた値が数値であるかどうかを確認します。
|
|
5
|
-
* @param value - The value to be checked. ���認する値。
|
|
6
|
-
* @returns {boolean} - Whether the value is a number. ��が数値であるかどうか。
|
|
7
|
-
*/
|
|
8
|
-
static isNumber(value: any) {
|
|
9
|
-
if (value == null) {
|
|
10
|
-
return false;
|
|
11
|
-
} else if (value instanceof Date) {
|
|
12
|
-
return false;
|
|
13
|
-
} else if (value instanceof Array) {
|
|
14
|
-
return false;
|
|
15
|
-
} else if (typeof(value) == 'string') {
|
|
16
|
-
if (value == "") {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return isNaN(Number(value)) == false;
|
|
22
|
-
}
|
|
23
|
-
}
|
package/src/Utils/StringUtil.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
export default class StringUtil {
|
|
2
|
-
/**
|
|
3
|
-
* Validates if the given value is a valid UUID
|
|
4
|
-
* 与えられた値が有効なUUIDであるかどうかを検証します
|
|
5
|
-
* @param value - The value to be validated, 検証する値
|
|
6
|
-
* @returns {boolean} - Whether the value is a valid UUID, 値が有効なUUIDであるかどうか
|
|
7
|
-
*/
|
|
8
|
-
static isUUID(value: any) {
|
|
9
|
-
if (typeof value !== 'string') {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const pattern = new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$');
|
|
14
|
-
return pattern.test(value);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 小文字スネークからキャピタルケースに変換
|
|
19
|
-
* @param {string} value スネーク文字列
|
|
20
|
-
* @returns キャピタル文字列
|
|
21
|
-
*/
|
|
22
|
-
static formatFromSnakeToCamel(value: string) {
|
|
23
|
-
const regex = /_[a-z]/g;
|
|
24
|
-
let capital = value.replace(regex,
|
|
25
|
-
function(matchChar) {
|
|
26
|
-
return String.fromCharCode(matchChar.charCodeAt(1) - 0x20);
|
|
27
|
-
}
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
// "_1"や"_@"のパターンを考慮して、_を省く(この使い方はあまりないと思いますが...)
|
|
31
|
-
return capital.replaceAll("_", "");
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
import { _Object, DeleteObjectsCommand, GetObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client, ScanRange } from '@aws-sdk/client-s3';
|
|
2
|
-
import { Base64Client } from './Base64Client';
|
|
3
|
-
import { UnprocessableException } from '../exceptions/Exception';
|
|
4
|
-
import axios from 'axios';
|
|
5
|
-
|
|
6
|
-
type IUploadResponse = {
|
|
7
|
-
url: string;
|
|
8
|
-
fileName: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class AwsS3Client {
|
|
12
|
-
private client: S3Client;
|
|
13
|
-
|
|
14
|
-
private readonly bucketName;
|
|
15
|
-
private readonly region;
|
|
16
|
-
get UrlPrefix(): string {
|
|
17
|
-
return `https://${this.bucketName}.s3.${this.region}.amazonaws.com`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
constructor(params: {bucketName?: string, region?: string; accessKeyId?: string, secretAccessKey?: string}) {
|
|
21
|
-
if (params.bucketName === undefined) {
|
|
22
|
-
throw new Error("Please specify the bucketName.");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (params.region === undefined) {
|
|
26
|
-
throw new Error("Please specify the region.");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (params.accessKeyId === undefined) {
|
|
30
|
-
throw new Error("Please specify the accessKeyId.");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (params.secretAccessKey === undefined) {
|
|
34
|
-
throw new Error("Please specify the secretAccessKey.");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
this.client = new S3Client({
|
|
38
|
-
region: params.region,
|
|
39
|
-
credentials: {
|
|
40
|
-
accessKeyId: params.accessKeyId,
|
|
41
|
-
secretAccessKey: params.secretAccessKey
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
this.region = params.region;
|
|
46
|
-
this.bucketName = params.bucketName;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private makeKey(path: string, fileName?: string): string {
|
|
50
|
-
path = path.replace(/^\/|\/$/g, '');
|
|
51
|
-
if ((fileName ?? '').trim().length > 0) {
|
|
52
|
-
path += '/' + fileName;
|
|
53
|
-
}
|
|
54
|
-
return path;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
public url(path: string, fileName: string = '') {
|
|
58
|
-
path = path.replace(/^\/|\/$/g, '');
|
|
59
|
-
let url = `${this.UrlPrefix}`;
|
|
60
|
-
if (path !== '') {
|
|
61
|
-
url += '/' + path;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (fileName.trim().length > 0) {
|
|
65
|
-
url += '/' + fileName;
|
|
66
|
-
}
|
|
67
|
-
return url;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public async uploadJson(path: string, fileName: string, data: {[key: string]: any}) {
|
|
71
|
-
const command = new PutObjectCommand({
|
|
72
|
-
Bucket: this.bucketName,
|
|
73
|
-
Key: this.makeKey(path, fileName),
|
|
74
|
-
Body: JSON.stringify(data),
|
|
75
|
-
ContentType: 'text/plain; charset=utf-8'
|
|
76
|
-
});
|
|
77
|
-
await this.client.send(command);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public async uploadToPdf(path: string, fileName: string, base64Datas: Array<string>) {
|
|
81
|
-
const base64Client = new Base64Client();
|
|
82
|
-
const mergedPdfBase64 = await base64Client.mergeToPdfBase64(base64Datas);
|
|
83
|
-
|
|
84
|
-
const command = new PutObjectCommand({
|
|
85
|
-
Bucket: this.bucketName,
|
|
86
|
-
Key: this.makeKey(path, fileName),
|
|
87
|
-
Body: Buffer.from(mergedPdfBase64, 'base64'),
|
|
88
|
-
ContentEncoding: 'base64',
|
|
89
|
-
ContentType: 'application/pdf'
|
|
90
|
-
});
|
|
91
|
-
await this.client.send(command);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
public async uploadText(path: string, fileName: string, text: string) {
|
|
95
|
-
const command = new PutObjectCommand({
|
|
96
|
-
Bucket: this.bucketName,
|
|
97
|
-
Key: this.makeKey(path, fileName),
|
|
98
|
-
Body: text,
|
|
99
|
-
ContentType: 'text/plain; charset=utf-8'
|
|
100
|
-
});
|
|
101
|
-
await this.client.send(command);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
public async uploadBase64Data(path: string, fileName: string, base64Data: string) : Promise<IUploadResponse> {
|
|
105
|
-
const base64Client = new Base64Client();
|
|
106
|
-
|
|
107
|
-
const type = base64Client.getMimeType(base64Data);
|
|
108
|
-
const extension = {
|
|
109
|
-
'image/png': '.png',
|
|
110
|
-
'image/jpeg': '.jpeg',
|
|
111
|
-
'image/gif': '.gif',
|
|
112
|
-
'application/pdf': '.pdf'
|
|
113
|
-
}[type];
|
|
114
|
-
if (fileName.endsWith(extension) === false) {
|
|
115
|
-
fileName += extension;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const key = this.makeKey(path, fileName);
|
|
119
|
-
const command = new PutObjectCommand({
|
|
120
|
-
Bucket: this.bucketName,
|
|
121
|
-
Key: key,
|
|
122
|
-
Body: Buffer.from(base64Data, 'base64'),
|
|
123
|
-
ContentEncoding: 'base64',
|
|
124
|
-
ContentType: type
|
|
125
|
-
});
|
|
126
|
-
await this.client.send(command);
|
|
127
|
-
|
|
128
|
-
return {
|
|
129
|
-
url: `${this.UrlPrefix}/${key}`,
|
|
130
|
-
fileName: fileName
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
public async uploadFromUrl(path: string, fileName: string, url: string): Promise<IUploadResponse> {
|
|
135
|
-
try {
|
|
136
|
-
// URLからデータを取得
|
|
137
|
-
const response = await axios.get(url, {
|
|
138
|
-
responseType: 'arraybuffer',
|
|
139
|
-
timeout: 30000,
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
// Content-Typeを取得
|
|
143
|
-
const contentType = response.headers['content-type'] || 'application/octet-stream';
|
|
144
|
-
|
|
145
|
-
const key = this.makeKey(path, fileName);
|
|
146
|
-
const command = new PutObjectCommand({
|
|
147
|
-
Bucket: this.bucketName,
|
|
148
|
-
Key: key,
|
|
149
|
-
Body: Buffer.from(response.data),
|
|
150
|
-
ContentType: contentType,
|
|
151
|
-
ContentLength: response.data.length
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
await this.client.send(command);
|
|
155
|
-
|
|
156
|
-
// アップロードされたファイルのURLを返す
|
|
157
|
-
return {
|
|
158
|
-
url: this.url(path, fileName),
|
|
159
|
-
fileName: fileName
|
|
160
|
-
}
|
|
161
|
-
} catch (error) {
|
|
162
|
-
if (axios.isAxiosError(error)) {
|
|
163
|
-
if (error.response) {
|
|
164
|
-
throw new UnprocessableException(`Failed to download from URL. HTTP ${error.response.status}: ${error.response.statusText}`);
|
|
165
|
-
} else if (error.request) {
|
|
166
|
-
throw new UnprocessableException('Failed to connect to the URL. Please check if the URL is accessible.');
|
|
167
|
-
} else {
|
|
168
|
-
throw new UnprocessableException('Invalid URL format.');
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
throw new UnprocessableException('Failed to upload from URL.');
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
public async uploadStackText(path: string, fileName: string, text: string) {
|
|
176
|
-
let preText = await this.getText(path, fileName);
|
|
177
|
-
if (typeof preText === 'string') {
|
|
178
|
-
text = preText + '\n' + text;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
await this.uploadText(path, fileName, text);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
public async getText(path: string, fileName: string) : Promise<string | null> {
|
|
185
|
-
try {
|
|
186
|
-
const command = new GetObjectCommand({
|
|
187
|
-
Bucket: this.bucketName,
|
|
188
|
-
Key: this.makeKey(path, fileName),
|
|
189
|
-
});
|
|
190
|
-
const res = await this.client.send(command);
|
|
191
|
-
|
|
192
|
-
if (res.Body === undefined) {
|
|
193
|
-
throw new Error(`Failed to get text data. Response body is undefined.`);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (res.ContentType?.startsWith('text/') === false) {
|
|
197
|
-
throw new Error(`Cannot get text data from non-text file. ContentType: ${res.ContentType}`);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// v3ではBodyがReadableStreamなので、変換が必要
|
|
201
|
-
const chunks: Uint8Array[] = [];
|
|
202
|
-
if (res.Body && typeof res.Body === 'object' && 'getReader' in res.Body) {
|
|
203
|
-
// ReadableStreamの場合
|
|
204
|
-
const stream = res.Body as ReadableStream;
|
|
205
|
-
const reader = stream.getReader();
|
|
206
|
-
|
|
207
|
-
while (true) {
|
|
208
|
-
const { done, value } = await reader.read();
|
|
209
|
-
if (done) break;
|
|
210
|
-
chunks.push(value);
|
|
211
|
-
}
|
|
212
|
-
} else {
|
|
213
|
-
// Node.js Readableの場合
|
|
214
|
-
for await (const chunk of res.Body as any) {
|
|
215
|
-
chunks.push(chunk);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const buffer = Buffer.concat(chunks);
|
|
220
|
-
return buffer.toString('utf-8');
|
|
221
|
-
} catch (ex: unknown) {
|
|
222
|
-
if (ex instanceof Error && ex.name === 'NoSuchKey') {
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
throw ex;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
public async getFilesInDir(path: string): Promise<Array<_Object>> {
|
|
230
|
-
const listCommand = new ListObjectsV2Command({
|
|
231
|
-
Bucket: this.bucketName,
|
|
232
|
-
Prefix: this.makeKey(path),
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
const data = await this.client.send(listCommand);
|
|
236
|
-
return data.Contents ?? [];
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
public async getDataFronJson<T = any>(path: string, fileName: string): Promise<T> {
|
|
240
|
-
const command = new GetObjectCommand({
|
|
241
|
-
Bucket: this.bucketName,
|
|
242
|
-
Key: this.makeKey(path, fileName),
|
|
243
|
-
});
|
|
244
|
-
const res = await this.client.send(command);
|
|
245
|
-
|
|
246
|
-
if (res.Body === undefined) {
|
|
247
|
-
throw new Error(`Failed to get JSON data. Response body is undefined.`);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (res.ContentType !== 'application/json') {
|
|
251
|
-
throw new Error(`Cannot get JSON data from non-JSON file. ContentType: ${res.ContentType}`);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// v3ではBodyがReadableなので、変換が必要
|
|
255
|
-
const chunks: Uint8Array[] = [];
|
|
256
|
-
for await (const chunk of res.Body as any) {
|
|
257
|
-
chunks.push(chunk);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const buffer = Buffer.concat(chunks);
|
|
261
|
-
const jsonString = buffer.toString('utf-8');
|
|
262
|
-
return JSON.parse(jsonString) as T;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
public async deleteFile(path: string, fileName: string): Promise<void> {
|
|
266
|
-
const key = this.makeKey(path, fileName);
|
|
267
|
-
const command = new DeleteObjectsCommand({
|
|
268
|
-
Bucket: this.bucketName,
|
|
269
|
-
Delete: {
|
|
270
|
-
Objects: [{ Key: key }]
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
await this.client.send(command);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
public async deleteDir(path: string): Promise<void> {
|
|
277
|
-
const files = await this.getFilesInDir(path);
|
|
278
|
-
if (files.length > 0) {
|
|
279
|
-
const deleteCommand = new DeleteObjectsCommand({
|
|
280
|
-
Bucket: this.bucketName,
|
|
281
|
-
Delete: {
|
|
282
|
-
Objects: files.map((file) => ({ Key: file.Key })),
|
|
283
|
-
},
|
|
284
|
-
});
|
|
285
|
-
await this.client.send(deleteCommand);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
public async deleteFromUrl(url: string, isFileUrl: boolean = true): Promise<void> {
|
|
290
|
-
const path = url.replace(this.UrlPrefix + '/', '');
|
|
291
|
-
if (url === path) {
|
|
292
|
-
throw new UnprocessableException('The specified URL cannot be deleted because the bucket and region do not match.');
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (path.trim() === "") {
|
|
296
|
-
throw new UnprocessableException('This URL is invalid.');
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (isFileUrl) {
|
|
300
|
-
const pathSplits = path.split('/');
|
|
301
|
-
const file = pathSplits.pop();
|
|
302
|
-
if (file === undefined) {
|
|
303
|
-
throw new UnprocessableException('This URL is invalid.');
|
|
304
|
-
}
|
|
305
|
-
await this.deleteFile(pathSplits.join('/'), file);
|
|
306
|
-
} else {
|
|
307
|
-
await this.deleteDir(path);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|