@alloy-framework/core 0.4.0 β 0.14.0
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/package.json +3 -3
- package/src/app/AlloyApp.js +0 -610
- package/src/config/AlloyConfig.js +0 -131
- package/src/data/AlloyModel.js +0 -405
- package/src/data/AlloyMongoModel.js +0 -265
- package/src/data/AlloyRedisModel.js +0 -158
- package/src/data/GooseValidator.js +0 -168
- package/src/data/index.js +0 -6
- package/src/data/validationHelper.js +0 -79
- package/src/http/AlloyController.js +0 -322
- package/src/http/AlloyRouter.js +0 -130
- package/src/http/Validator.js +0 -52
- package/src/http/index.js +0 -6
- package/src/index.d.ts +0 -345
- package/src/index.js +0 -43
- package/src/security/AlloyCrypto.js +0 -96
- package/src/security/AlloySession.js +0 -81
- package/src/security/index.js +0 -5
- package/src/service/AlloyService.js +0 -171
- package/src/util/AlloyError.js +0 -23
- package/src/util/Pagination.js +0 -39
- package/src/util/index.js +0 -6
- package/src/ws/AlloyWebSocket.js +0 -130
- package/wasm/alloy_client_wasm.d.ts +0 -174
- package/wasm/alloy_client_wasm.js +0 -1215
- package/wasm/alloy_client_wasm_bg.wasm +0 -0
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import native from '@alloy-framework/rust';
|
|
2
|
-
import { AlloyModel } from './AlloyModel.js';
|
|
3
|
-
import { validateForSave, validateForUpdate, applyMongoDefaults } from './validationHelper.js';
|
|
4
|
-
import { AlloyError } from '../util/AlloyError.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* π Alloy MongoDB μ μ© λͺ¨λΈ
|
|
8
|
-
* MongoDBμ find, insertOne, updateOne, aggregate λ± μ§κ΄μ APIλ₯Ό μ 곡ν©λλ€.
|
|
9
|
-
* λ΄λΆμ μΌλ‘ Rustμ mongoCommand (run_command)λ₯Ό λνν©λλ€.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* class ActivityLogs extends AlloyMongoModel {
|
|
13
|
-
* constructor() { super('activity_logs'); }
|
|
14
|
-
* }
|
|
15
|
-
*
|
|
16
|
-
* const logs = await new ActivityLogs().find({ domain: 'AUTH' }, { sort: { _id: -1 }, limit: 50 });
|
|
17
|
-
*/
|
|
18
|
-
export class AlloyMongoModel extends AlloyModel {
|
|
19
|
-
/**
|
|
20
|
-
* @param {string} collection - MongoDB 컬λ μ
μ΄λ¦
|
|
21
|
-
* @param {string} [store='mongo_main'] - alloy.confμ μ μλ MongoDB μ€ν μ΄ μ΄λ¦
|
|
22
|
-
*/
|
|
23
|
-
constructor(collection, store = 'mongo_main') {
|
|
24
|
-
super(collection, store); // AlloyModel μμ±μ: table, store, _native μ΄κΈ°ν
|
|
25
|
-
/** @type {string} 컬λ μ
μ΄λ¦ (MongoDB μ μ© λ³μΉ) */
|
|
26
|
-
this.collection = collection;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
30
|
-
// π μ‘°ν (Read)
|
|
31
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* λ¬Έμ λ°°μ΄ μ‘°ν
|
|
35
|
-
* @param {object} [filter={}] - κ²μ 쑰건
|
|
36
|
-
* @param {object} [options={}] - μ‘°ν μ΅μ
(sort, limit, skip, projection)
|
|
37
|
-
* @returns {Promise<object[]>} λ¬Έμ λ°°μ΄
|
|
38
|
-
*/
|
|
39
|
-
async find(filter = {}, options = {}) {
|
|
40
|
-
const cmd = { find: this.collection, filter };
|
|
41
|
-
if (options.sort) cmd.sort = options.sort;
|
|
42
|
-
if (options.limit != null) cmd.limit = options.limit;
|
|
43
|
-
if (options.skip != null) cmd.skip = options.skip;
|
|
44
|
-
if (options.projection) cmd.projection = options.projection;
|
|
45
|
-
|
|
46
|
-
const result = await this._native.mongoCommand(JSON.stringify(cmd));
|
|
47
|
-
return result?.cursor?.firstBatch || [];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* λ¨μΌ λ¬Έμ μ‘°ν
|
|
52
|
-
* @param {object} [filter={}] - κ²μ 쑰건
|
|
53
|
-
* @param {object} [options={}] - μ‘°ν μ΅μ
|
|
54
|
-
* @returns {Promise<object|null>} λ¬Έμ λλ null
|
|
55
|
-
*/
|
|
56
|
-
async findOne(filter = {}, options = {}) {
|
|
57
|
-
const docs = await this.find(filter, { ...options, limit: 1 });
|
|
58
|
-
return docs[0] || null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* λ¬Έμ μ μ‘°ν
|
|
63
|
-
* - filter μΈμκ° μμΌλ©΄ mongoCommand μ§μ μ€ν
|
|
64
|
-
* - filter μμ΄ μ²΄μ΄λ(.where().count()) μ λΆλͺ¨ AlloyModel.count() μμ
|
|
65
|
-
* @param {object} [filter] - κ²μ 쑰건 (μμΌλ©΄ 체μ΄λ 쑰건 μ¬μ©)
|
|
66
|
-
* @returns {Promise<number>}
|
|
67
|
-
*/
|
|
68
|
-
async count(filter) {
|
|
69
|
-
// λͺ
μμ filterκ° μμΌλ©΄ mongoCommand μ§μ μ€ν
|
|
70
|
-
if (filter && Object.keys(filter).length > 0) {
|
|
71
|
-
const result = await this._native.mongoCommand(
|
|
72
|
-
JSON.stringify({ count: this.collection, query: filter }),
|
|
73
|
-
);
|
|
74
|
-
return result?.n || 0;
|
|
75
|
-
}
|
|
76
|
-
// 체μ΄λ where 쑰건 μ¬μ© β λΆλͺ¨ AlloyModel.count() (aggregate $sum:1)
|
|
77
|
-
return super.count();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
81
|
-
// βοΈ μ½μ
(Create)
|
|
82
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* λ¨μΌ λ¬Έμ μ½μ
|
|
86
|
-
* @param {object} doc - μ½μ
ν λ¬Έμ
|
|
87
|
-
* @returns {Promise<object>} { ok, n }
|
|
88
|
-
*/
|
|
89
|
-
async insertOne(doc) {
|
|
90
|
-
const schema = this.constructor.schema;
|
|
91
|
-
doc = await validateForSave(schema, doc);
|
|
92
|
-
applyMongoDefaults(schema, doc);
|
|
93
|
-
|
|
94
|
-
const cmd = { insert: this.collection, documents: [doc], ordered: true };
|
|
95
|
-
const result = await this._native.mongoCommand(JSON.stringify(cmd));
|
|
96
|
-
this._assertOk(result, 'insertOne');
|
|
97
|
-
return { ok: true, n: result?.n || 1 };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* λ€μ€ λ¬Έμ μ½μ
|
|
102
|
-
* @param {object[]} docs - μ½μ
ν λ¬Έμ λ°°μ΄
|
|
103
|
-
* @param {object} [options={}] - μ΅μ
{ ordered: true }
|
|
104
|
-
* @returns {Promise<object>} { ok, n }
|
|
105
|
-
*/
|
|
106
|
-
async insertMany(docs, options = {}) {
|
|
107
|
-
const schema = this.constructor.schema;
|
|
108
|
-
|
|
109
|
-
// κ° λ¬Έμμ GooseValidator κ²μ¦ + κΈ°λ³Έκ° μ£Όμ
|
|
110
|
-
for (const doc of docs) {
|
|
111
|
-
await validateForSave(schema, doc);
|
|
112
|
-
applyMongoDefaults(schema, doc);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const cmd = {
|
|
116
|
-
insert: this.collection,
|
|
117
|
-
documents: docs,
|
|
118
|
-
ordered: options.ordered !== false,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const result = await this._native.mongoCommand(JSON.stringify(cmd));
|
|
122
|
-
this._assertOk(result, 'insertMany');
|
|
123
|
-
return { ok: true, n: result?.n || docs.length };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
127
|
-
// π μμ (Update)
|
|
128
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* λ¨μΌ λ¬Έμ μμ
|
|
132
|
-
* @param {object} filter - κ²μ 쑰건
|
|
133
|
-
* @param {object} update - μμ λ΄μ© (μ: { $set: { name: 'new' } })
|
|
134
|
-
* @param {object} [options={}] - μ΅μ
{ upsert, arrayFilters, hint, collation }
|
|
135
|
-
* @returns {Promise<object>} { ok, nModified, upserted }
|
|
136
|
-
*/
|
|
137
|
-
async updateOne(filter, update, options = {}) {
|
|
138
|
-
// $set λ°μ΄ν°μ λν΄ μ€ν€λ§ κ²μ¦ μ μ©
|
|
139
|
-
if (update?.$set) {
|
|
140
|
-
const schema = this.constructor.schema;
|
|
141
|
-
update.$set = await validateForUpdate(schema, update.$set);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const spec = { q: filter, u: update, multi: false };
|
|
145
|
-
if (options.upsert) spec.upsert = true;
|
|
146
|
-
if (options.arrayFilters) spec.arrayFilters = options.arrayFilters;
|
|
147
|
-
if (options.hint) spec.hint = options.hint;
|
|
148
|
-
if (options.collation) spec.collation = options.collation;
|
|
149
|
-
|
|
150
|
-
const cmd = { update: this.collection, updates: [spec] };
|
|
151
|
-
const result = await this._native.mongoCommand(JSON.stringify(cmd));
|
|
152
|
-
this._assertOk(result, 'updateOne');
|
|
153
|
-
return { ok: true, nModified: result?.nModified || 0, upserted: result?.upserted || null };
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* λ€μ€ λ¬Έμ μμ
|
|
158
|
-
* @param {object} filter - κ²μ 쑰건
|
|
159
|
-
* @param {object} update - μμ λ΄μ©
|
|
160
|
-
* @param {object} [options={}] - μ΅μ
|
|
161
|
-
* @returns {Promise<object>} { ok, nModified }
|
|
162
|
-
*/
|
|
163
|
-
async updateMany(filter, update, options = {}) {
|
|
164
|
-
// $set λ°μ΄ν°μ λν΄ μ€ν€λ§ κ²μ¦ μ μ©
|
|
165
|
-
if (update?.$set) {
|
|
166
|
-
const schema = this.constructor.schema;
|
|
167
|
-
update.$set = await validateForUpdate(schema, update.$set);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const spec = { q: filter, u: update, multi: true };
|
|
171
|
-
if (options.upsert) spec.upsert = true;
|
|
172
|
-
if (options.arrayFilters) spec.arrayFilters = options.arrayFilters;
|
|
173
|
-
|
|
174
|
-
const cmd = { update: this.collection, updates: [spec] };
|
|
175
|
-
const result = await this._native.mongoCommand(JSON.stringify(cmd));
|
|
176
|
-
this._assertOk(result, 'updateMany');
|
|
177
|
-
return { ok: true, nModified: result?.nModified || 0 };
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
181
|
-
// ποΈ μμ (Delete)
|
|
182
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* λ¨μΌ λ¬Έμ μμ
|
|
186
|
-
* @param {object} filter - κ²μ 쑰건
|
|
187
|
-
* @returns {Promise<object>} { ok, n }
|
|
188
|
-
*/
|
|
189
|
-
async deleteOne(filter) {
|
|
190
|
-
const cmd = { delete: this.collection, deletes: [{ q: filter, limit: 1 }] };
|
|
191
|
-
const result = await this._native.mongoCommand(JSON.stringify(cmd));
|
|
192
|
-
this._assertOk(result, 'deleteOne');
|
|
193
|
-
return { ok: true, n: result?.n || 0 };
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* λ€μ€ λ¬Έμ μμ
|
|
198
|
-
* @param {object} filter - κ²μ 쑰건
|
|
199
|
-
* @returns {Promise<object>} { ok, n }
|
|
200
|
-
*/
|
|
201
|
-
async deleteMany(filter) {
|
|
202
|
-
const cmd = { delete: this.collection, deletes: [{ q: filter, limit: 0 }] };
|
|
203
|
-
const result = await this._native.mongoCommand(JSON.stringify(cmd));
|
|
204
|
-
this._assertOk(result, 'deleteMany');
|
|
205
|
-
return { ok: true, n: result?.n || 0 };
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
209
|
-
// π μ§κ³ (Aggregate)
|
|
210
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* MongoDB Aggregation Pipeline μ€ν
|
|
214
|
-
* @param {object[]} pipeline - νμ΄νλΌμΈ μ€ν
μ΄μ§ λ°°μ΄
|
|
215
|
-
* @param {object} [options={}] - μ΅μ
{ collation, allowDiskUse }
|
|
216
|
-
* @returns {Promise<object[]>} κ²°κ³Ό λ°°μ΄
|
|
217
|
-
*/
|
|
218
|
-
async aggregate(pipeline, options = {}) {
|
|
219
|
-
const cmd = { aggregate: this.collection, pipeline, cursor: {} };
|
|
220
|
-
if (options.collation) cmd.collation = options.collation;
|
|
221
|
-
if (options.allowDiskUse) cmd.allowDiskUse = true;
|
|
222
|
-
|
|
223
|
-
const result = await this._native.mongoCommand(JSON.stringify(cmd));
|
|
224
|
-
return result?.cursor?.firstBatch || [];
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
228
|
-
// π 체μ΄λ νΈν API (AlloyModel μμ)
|
|
229
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
230
|
-
// select, where, orWhere, whereIn, whereNull, limit, offset, orderBy,
|
|
231
|
-
// get, first, count, update, delete λ±μ AlloyModelμμ μμ
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* 체μ΄λ λ°©μ μ½μ
|
|
235
|
-
* @param {object} data - μ½μ
ν λ°μ΄ν°
|
|
236
|
-
* @returns {Promise<object>}
|
|
237
|
-
*/
|
|
238
|
-
async save(data) {
|
|
239
|
-
const schema = this.constructor.schema;
|
|
240
|
-
data = await validateForSave(schema, data);
|
|
241
|
-
applyMongoDefaults(schema, data);
|
|
242
|
-
|
|
243
|
-
return await this._native.save(JSON.stringify(data));
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Raw MongoDB 컀맨λ μ€ν
|
|
248
|
-
* @param {object} cmdObj - MongoDB 컀맨λ κ°μ²΄
|
|
249
|
-
* @returns {Promise<object>}
|
|
250
|
-
*/
|
|
251
|
-
async command(cmdObj) {
|
|
252
|
-
return await this._native.mongoCommand(JSON.stringify(cmdObj));
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* μλ΅ κ²μ¦ (ok !== 1μ΄λ©΄ μλ¬)
|
|
257
|
-
* @private
|
|
258
|
-
*/
|
|
259
|
-
_assertOk(result, operation) {
|
|
260
|
-
const ok = result?.ok;
|
|
261
|
-
if (ok !== 1 && ok !== 1.0) {
|
|
262
|
-
throw new AlloyError('MONGO_OPERATION_FAILED', `Mongo ${operation} Failed: ${result?.errmsg || 'Unknown error'}`, 500);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import native from '@alloy-framework/rust';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* π΄ Alloy Redis λͺ¨λΈ
|
|
5
|
-
* Redisμ μμ£Ό μ¬μ©νλ λͺ
λ Ήμ μ§κ΄μ APIλ‘ μ 곡ν©λλ€.
|
|
6
|
-
* Rust N-APIμ AlloyRedisλ₯Ό λνν©λλ€.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* const redis = new AlloyRedisModel('cache');
|
|
10
|
-
* await redis.set('key', 'value', 300);
|
|
11
|
-
* const val = await redis.get('key');
|
|
12
|
-
*/
|
|
13
|
-
export class AlloyRedisModel {
|
|
14
|
-
/**
|
|
15
|
-
* @param {string} [store='cache'] - alloy.confμ μ μλ Redis μ€ν μ΄ μ΄λ¦
|
|
16
|
-
*/
|
|
17
|
-
constructor(store = 'cache') {
|
|
18
|
-
/** @type {string} μ€ν μ΄ μ΄λ¦ */
|
|
19
|
-
this.store = store;
|
|
20
|
-
/** @type {import('@alloy/rust').AlloyRedis} λ€μ΄ν°λΈ Redis μΈμ€ν΄μ€ */
|
|
21
|
-
this._native = new native.AlloyRedis(store);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
25
|
-
// π String λͺ
λ Ή
|
|
26
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* ν€-κ° μ μ₯ (TTL μ΅μ
)
|
|
30
|
-
* @param {string} key
|
|
31
|
-
* @param {string} value
|
|
32
|
-
* @param {number} [ttlSeconds] - TTL (μ΄, λ―Έμ§μ μ μꡬ)
|
|
33
|
-
* @returns {Promise<void>}
|
|
34
|
-
*/
|
|
35
|
-
async set(key, value, ttlSeconds) {
|
|
36
|
-
return await this._native.set(key, String(value), ttlSeconds || 0);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* ν€ μ‘°ν
|
|
41
|
-
* @param {string} key
|
|
42
|
-
* @returns {Promise<string|null>}
|
|
43
|
-
*/
|
|
44
|
-
async get(key) {
|
|
45
|
-
return await this._native.get(key);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* ν€ μμ
|
|
50
|
-
* @param {string} key
|
|
51
|
-
* @returns {Promise<void>}
|
|
52
|
-
*/
|
|
53
|
-
async del(key) {
|
|
54
|
-
return await this._native.del(key);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* ν€ μ‘΄μ¬ μ¬λΆ
|
|
59
|
-
* @param {string} key
|
|
60
|
-
* @returns {Promise<boolean>}
|
|
61
|
-
*/
|
|
62
|
-
async exists(key) {
|
|
63
|
-
return await this._native.exists(key);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
67
|
-
// π Hash λͺ
λ Ή
|
|
68
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Hash νλ μ€μ
|
|
72
|
-
* @param {string} key - Hash ν€
|
|
73
|
-
* @param {string} field - νλλͺ
|
|
74
|
-
* @param {string} value - κ°
|
|
75
|
-
* @returns {Promise<void>}
|
|
76
|
-
*/
|
|
77
|
-
async hset(key, field, value) {
|
|
78
|
-
return await this._native.hset(key, field, String(value));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Hash νλ μ‘°ν
|
|
83
|
-
* @param {string} key
|
|
84
|
-
* @param {string} field
|
|
85
|
-
* @returns {Promise<string|null>}
|
|
86
|
-
*/
|
|
87
|
-
async hget(key, field) {
|
|
88
|
-
return await this._native.hget(key, field);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Hash νλ μμ
|
|
93
|
-
* @param {string} key
|
|
94
|
-
* @param {string} field
|
|
95
|
-
* @returns {Promise<void>}
|
|
96
|
-
*/
|
|
97
|
-
async hdel(key, field) {
|
|
98
|
-
return await this._native.hdel(key, field);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Hash μ 체 μ‘°ν
|
|
103
|
-
* @param {string} key
|
|
104
|
-
* @returns {Promise<object>} ν€-κ° μ
|
|
105
|
-
*/
|
|
106
|
-
async hgetall(key) {
|
|
107
|
-
return await this._native.hgetall(key);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
111
|
-
// π List λͺ
λ Ή
|
|
112
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* List μΌμͺ½ νΈμ
|
|
116
|
-
* @param {string} key
|
|
117
|
-
* @param {string} value
|
|
118
|
-
* @returns {Promise<void>}
|
|
119
|
-
*/
|
|
120
|
-
async lpush(key, value) {
|
|
121
|
-
return await this._native.lpush(key, String(value));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* List μ€λ₯Έμͺ½ νΈμ
|
|
126
|
-
* @param {string} key
|
|
127
|
-
* @param {string} value
|
|
128
|
-
* @returns {Promise<void>}
|
|
129
|
-
*/
|
|
130
|
-
async rpush(key, value) {
|
|
131
|
-
return await this._native.rpush(key, String(value));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* List λ²μ μ‘°ν
|
|
136
|
-
* @param {string} key
|
|
137
|
-
* @param {number} [start=0]
|
|
138
|
-
* @param {number} [stop=-1]
|
|
139
|
-
* @returns {Promise<string[]>}
|
|
140
|
-
*/
|
|
141
|
-
async lrange(key, start = 0, stop = -1) {
|
|
142
|
-
return await this._native.lrange(key, start, stop);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
146
|
-
// π§ μ νΈλ¦¬ν°
|
|
147
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Raw Redis λͺ
λ Ή μ€ν
|
|
151
|
-
* @param {string} cmd - λͺ
λ Ήμ΄ (μ: 'TTL')
|
|
152
|
-
* @param {string[]} args - μΈμ λ°°μ΄
|
|
153
|
-
* @returns {Promise<any>}
|
|
154
|
-
*/
|
|
155
|
-
async command(cmd, ...args) {
|
|
156
|
-
return await this._native.rawCommand(cmd, args);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { AlloyError } from '../util/AlloyError.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* π¦’ AlloyGoose μ€ν€λ§ μλ κ²μ¦κΈ°
|
|
5
|
-
*
|
|
6
|
-
* AlloyGoose μ€ν€λ§μ `fields` μ μλ₯Ό κΈ°λ°μΌλ‘ λ°μ΄ν°λ₯Ό μλ κ²μ¦ν©λλ€.
|
|
7
|
-
* Joi μμ΄ κΈ°λ³Έμ μΈ νμ
/νμκ°/κΈΈμ΄/μ΄κ±°ν κ²μ¦μ μνν©λλ€.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* GooseValidator.validateInsert(schema.fields, { username: 'admin', age: 25 });
|
|
11
|
-
* GooseValidator.validateUpdate(schema.fields, { age: 30 });
|
|
12
|
-
*/
|
|
13
|
-
export class GooseValidator {
|
|
14
|
-
/** μ«μ νμ
λͺ©λ‘ */
|
|
15
|
-
static #NUMBER_TYPES = new Set([
|
|
16
|
-
'int', 'bigint', 'mediumint', 'smallint', 'tinyint',
|
|
17
|
-
'float', 'double', 'decimal', 'number',
|
|
18
|
-
]);
|
|
19
|
-
|
|
20
|
-
/** λ¬Έμμ΄ νμ
λͺ©λ‘ */
|
|
21
|
-
static #STRING_TYPES = new Set([
|
|
22
|
-
'string', 'text', 'mediumtext', 'longtext', 'enum',
|
|
23
|
-
]);
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* INSERT μ© κ²μ¦ β required νλ μ²΄ν¬ ν¬ν¨
|
|
27
|
-
* @param {object} fields - AlloyGoose fields μ μ
|
|
28
|
-
* @param {object} data - μ½μ
ν λ°μ΄ν°
|
|
29
|
-
* @throws {Error} κ²μ¦ μ€ν¨ μ (statusCode: 400)
|
|
30
|
-
*/
|
|
31
|
-
static validateInsert(fields, data) {
|
|
32
|
-
const errors = [];
|
|
33
|
-
|
|
34
|
-
for (const [name, def] of Object.entries(fields)) {
|
|
35
|
-
// auto_increment PKλ κ²μ¦ μ€ν΅
|
|
36
|
-
if (def.primary && def.auto_increment) continue;
|
|
37
|
-
// MongoDB _idλ μμ€ν
μμ±
|
|
38
|
-
if (name === '_id') continue;
|
|
39
|
-
|
|
40
|
-
const value = data[name];
|
|
41
|
-
|
|
42
|
-
// ββ required μ²΄ν¬ (INSERT μ μ©) ββ
|
|
43
|
-
const isRequired = def.required === true || def.nullable === false;
|
|
44
|
-
if (isRequired && (value === undefined || value === null)) {
|
|
45
|
-
// defaultκ° μμΌλ©΄ μλ μ£Όμ
λλ―λ‘ ν¨μ€
|
|
46
|
-
if (def.default !== undefined) continue;
|
|
47
|
-
errors.push(`'${name}' νλλ νμμ
λλ€`);
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// κ°μ΄ μμΌλ©΄ μ΄ν νμ
μ²΄ν¬ λΆνμ
|
|
52
|
-
if (value === undefined || value === null) continue;
|
|
53
|
-
|
|
54
|
-
// ββ νμ
μ²΄ν¬ ββ
|
|
55
|
-
this.#checkType(name, def, value, errors);
|
|
56
|
-
|
|
57
|
-
// ββ κΈΈμ΄ μ²΄ν¬ ββ
|
|
58
|
-
this.#checkLength(name, def, value, errors);
|
|
59
|
-
|
|
60
|
-
// ββ enum μ²΄ν¬ ββ
|
|
61
|
-
this.#checkEnum(name, def, value, errors);
|
|
62
|
-
|
|
63
|
-
// ββ νλλ³ Joi μΆκ° κ²μ¦ ββ
|
|
64
|
-
this.#checkValidator(name, def, value, errors);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (errors.length > 0) {
|
|
68
|
-
throw new AlloyError('VALIDATION_ERROR', `Validation Error: ${errors.join(', ')}`, 400);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* UPDATE μ© κ²μ¦ β required 무μ, μ 곡λ νλλ§ κ²μ¦
|
|
74
|
-
* @param {object} fields - AlloyGoose fields μ μ
|
|
75
|
-
* @param {object} data - μμ ν λ°μ΄ν°
|
|
76
|
-
* @throws {Error} κ²μ¦ μ€ν¨ μ (statusCode: 400)
|
|
77
|
-
*/
|
|
78
|
-
static validateUpdate(fields, data) {
|
|
79
|
-
const errors = [];
|
|
80
|
-
|
|
81
|
-
for (const [name, value] of Object.entries(data)) {
|
|
82
|
-
const def = fields[name];
|
|
83
|
-
// μ€ν€λ§μ μλ νλλ 건λλ (MongoDB μ μ°μ±)
|
|
84
|
-
if (!def) continue;
|
|
85
|
-
// null νμ© μ²΄ν¬
|
|
86
|
-
if (value === null) {
|
|
87
|
-
if (def.nullable === false || def.required === true) {
|
|
88
|
-
errors.push(`'${name}' νλλ NULLμΌ μ μμ΅λλ€`);
|
|
89
|
-
}
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
this.#checkType(name, def, value, errors);
|
|
94
|
-
this.#checkLength(name, def, value, errors);
|
|
95
|
-
this.#checkEnum(name, def, value, errors);
|
|
96
|
-
this.#checkValidator(name, def, value, errors);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (errors.length > 0) {
|
|
100
|
-
throw new AlloyError('VALIDATION_ERROR', `Validation Error: ${errors.join(', ')}`, 400);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
105
|
-
// π Private κ²μ¦ ν¬νΌ
|
|
106
|
-
// ββββββββββββββββββββββββββββββββββββββ
|
|
107
|
-
|
|
108
|
-
static #checkType(name, def, value, errors) {
|
|
109
|
-
const ft = def.type;
|
|
110
|
-
if (!ft) return;
|
|
111
|
-
|
|
112
|
-
if (this.#NUMBER_TYPES.has(ft)) {
|
|
113
|
-
if (typeof value !== 'number' || Number.isNaN(value)) {
|
|
114
|
-
errors.push(`'${name}' νλλ μ«μμ¬μΌ ν©λλ€ (type: ${ft})`);
|
|
115
|
-
}
|
|
116
|
-
} else if (this.#STRING_TYPES.has(ft)) {
|
|
117
|
-
if (typeof value !== 'string') {
|
|
118
|
-
errors.push(`'${name}' νλλ λ¬Έμμ΄μ΄μ΄μΌ ν©λλ€ (type: ${ft})`);
|
|
119
|
-
}
|
|
120
|
-
} else if (ft === 'boolean') {
|
|
121
|
-
if (typeof value !== 'boolean') {
|
|
122
|
-
errors.push(`'${name}' νλλ booleanμ΄μ΄μΌ ν©λλ€`);
|
|
123
|
-
}
|
|
124
|
-
} else if (ft === 'json' || ft === 'object') {
|
|
125
|
-
if (typeof value !== 'object') {
|
|
126
|
-
errors.push(`'${name}' νλλ κ°μ²΄μ¬μΌ ν©λλ€ (type: ${ft})`);
|
|
127
|
-
}
|
|
128
|
-
} else if (ft === 'array') {
|
|
129
|
-
if (!Array.isArray(value)) {
|
|
130
|
-
errors.push(`'${name}' νλλ λ°°μ΄μ΄μ΄μΌ ν©λλ€`);
|
|
131
|
-
}
|
|
132
|
-
} else if (ft === 'datetime' || ft === 'timestamp' || ft === 'date') {
|
|
133
|
-
// λ¬Έμμ΄ λλ Date κ°μ²΄ νμ©
|
|
134
|
-
if (typeof value !== 'string' && !(value instanceof Date)) {
|
|
135
|
-
errors.push(`'${name}' νλλ λ μ§ λ¬Έμμ΄ λλ Date κ°μ²΄μ¬μΌ ν©λλ€`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** κΈΈμ΄ μ²΄ν¬ μ μΈ νμ
(fractional seconds precision) */
|
|
141
|
-
static #SKIP_LENGTH_TYPES = new Set(['datetime', 'timestamp', 'date']);
|
|
142
|
-
|
|
143
|
-
static #checkLength(name, def, value, errors) {
|
|
144
|
-
if (this.#SKIP_LENGTH_TYPES.has(def.type)) return;
|
|
145
|
-
if (def.length && typeof value === 'string' && value.length > def.length) {
|
|
146
|
-
errors.push(`'${name}' νλλ ${def.length}μ μ΄νμ¬μΌ ν©λλ€ (νμ¬: ${value.length}μ)`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
static #checkEnum(name, def, value, errors) {
|
|
151
|
-
const enumValues = def.enum || def.enum_values;
|
|
152
|
-
if (enumValues && Array.isArray(enumValues)) {
|
|
153
|
-
if (!enumValues.includes(value)) {
|
|
154
|
-
errors.push(`'${name}' νλλ [${enumValues.join(', ')}] μ€ νλμ¬μΌ ν©λλ€`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
static #checkValidator(name, def, value, errors) {
|
|
160
|
-
if (def.validator && typeof def.validator.validate === 'function') {
|
|
161
|
-
const { error } = def.validator.validate(value);
|
|
162
|
-
if (error) {
|
|
163
|
-
const details = error.details?.map(d => d.message).join(', ') || error.message;
|
|
164
|
-
errors.push(`'${name}': ${details}`);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
package/src/data/index.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* π§ κ²μ¦/κΈ°λ³Έκ° κ³΅ν΅ ν¬νΌ
|
|
3
|
-
* AlloyModel, AlloyMongoModelμμ μ€λ³΅λλ κ²μ¦ + κΈ°λ³Έκ° λ‘μ§μ ν΅ν©ν©λλ€.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* INSERTμ© λ°μ΄ν° κ²μ¦ (AlloyGoose + legacy Joi μλ λΆκΈ°)
|
|
8
|
-
* @param {object|null} schema - λͺ¨λΈμ static schema
|
|
9
|
-
* @param {object} data - μ½μ
ν λ°μ΄ν°
|
|
10
|
-
* @returns {object} κ²μ¦/μ μ λ λ°μ΄ν°
|
|
11
|
-
*/
|
|
12
|
-
export async function validateForSave(schema, data) {
|
|
13
|
-
if (!schema) return data;
|
|
14
|
-
|
|
15
|
-
// 1) AlloyGoose μ€ν€λ§ (fields κΈ°λ°)
|
|
16
|
-
if (schema.fields && typeof schema.fields === 'object') {
|
|
17
|
-
const { GooseValidator } = await import('./GooseValidator.js');
|
|
18
|
-
GooseValidator.validateInsert(schema.fields, data);
|
|
19
|
-
return data;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// 2) legacy Joi μ€ν€λ§ (validate λ©μλ)
|
|
23
|
-
if (typeof schema.validate === 'function') {
|
|
24
|
-
const { Validator } = await import('../http/Validator.js');
|
|
25
|
-
return Validator.validate(schema, data);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return data;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* UPDATEμ© λ°μ΄ν° κ²μ¦ (AlloyGoose + legacy Joi μλ λΆκΈ°)
|
|
33
|
-
* @param {object|null} schema - λͺ¨λΈμ static schema
|
|
34
|
-
* @param {object} data - μμ ν λ°μ΄ν°
|
|
35
|
-
* @returns {object} κ²μ¦/μ μ λ λ°μ΄ν°
|
|
36
|
-
*/
|
|
37
|
-
export async function validateForUpdate(schema, data) {
|
|
38
|
-
if (!schema) return data;
|
|
39
|
-
|
|
40
|
-
// 1) AlloyGoose μ€ν€λ§ (fields κΈ°λ° β μ 곡λ νλλ§ κ²μ¦)
|
|
41
|
-
if (schema.fields && typeof schema.fields === 'object') {
|
|
42
|
-
const { GooseValidator } = await import('./GooseValidator.js');
|
|
43
|
-
GooseValidator.validateUpdate(schema.fields, data);
|
|
44
|
-
return data;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 2) legacy Joi μ€ν€λ§ (partial κ²μ¦)
|
|
48
|
-
if (typeof schema.validate === 'function') {
|
|
49
|
-
const { Validator } = await import('../http/Validator.js');
|
|
50
|
-
return Validator.validate(schema, data, true);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return data;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* MongoDB κΈ°λ³Έκ° μλ μ£Όμ
(DDL DEFAULT μμΌλ―λ‘ μ± λ 벨μμ μ²λ¦¬)
|
|
58
|
-
* @param {object|null} schema - λͺ¨λΈμ static schema
|
|
59
|
-
* @param {object} data - μ½μ
ν λ°μ΄ν° (in-place μμ )
|
|
60
|
-
*/
|
|
61
|
-
export function applyMongoDefaults(schema, data) {
|
|
62
|
-
if (!schema?.fields || typeof schema.fields !== 'object') return;
|
|
63
|
-
|
|
64
|
-
for (const [fieldName, fieldDef] of Object.entries(schema.fields)) {
|
|
65
|
-
if (fieldName === '_id') continue;
|
|
66
|
-
if (data[fieldName] !== undefined) continue;
|
|
67
|
-
|
|
68
|
-
if (fieldDef.default !== undefined) {
|
|
69
|
-
if (fieldDef.default === 'CURRENT_TIMESTAMP' || fieldDef.default === 'NOW()') {
|
|
70
|
-
data[fieldName] = new Date().toISOString();
|
|
71
|
-
} else {
|
|
72
|
-
data[fieldName] = fieldDef.default;
|
|
73
|
-
}
|
|
74
|
-
} else {
|
|
75
|
-
// default λ―Έμ§μ νλλ nullλ‘ μ£Όμ
(MongoDB λ¬Έμμ νλ μ‘΄μ¬ λ³΄μ₯)
|
|
76
|
-
data[fieldName] = null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|