@aromix/core 0.3.2 → 0.4.1
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/index.d.ts +236 -64
- package/dist/index.js +366 -74
- package/package.json +10 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,82 +1,254 @@
|
|
|
1
1
|
import { AnySchema } from '@aromix/validator';
|
|
2
|
+
import { Db, InsertOneOptions, InsertOneResult, BulkWriteOptions, InsertManyResult, Filter, FindOptions, UpdateFilter, UpdateOptions, UpdateResult, ReplaceOptions, DeleteOptions, DeleteResult, FindOneAndUpdateOptions, FindOneAndDeleteOptions, FindOneAndReplaceOptions, CountDocumentsOptions, DistinctOptions, AggregateOptions, AggregationCursor, BulkWriteResult, CreateIndexesOptions, DropIndexesOptions } from 'mongodb';
|
|
3
|
+
import * as http from 'http';
|
|
4
|
+
import { IncomingMessage, ServerResponse } from 'http';
|
|
2
5
|
|
|
3
|
-
interface
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
interface KvEntityUserInput<Schema extends AnySchema> {
|
|
7
|
+
name: string;
|
|
8
|
+
model: Schema;
|
|
9
|
+
}
|
|
10
|
+
declare class KvEntity<Schema extends AnySchema> {
|
|
11
|
+
readonly state: KvEntityUserInput<Schema>;
|
|
12
|
+
private adapter;
|
|
13
|
+
constructor(userProvided: KvEntityUserInput<Schema>, internal: EntityBuilder.KvAdapter);
|
|
14
|
+
get(key: string): Promise<Schema['$select']>;
|
|
15
|
+
set(key: string, value: Schema['$insert']): Promise<void>;
|
|
6
16
|
delete(key: string): Promise<void>;
|
|
7
17
|
has(key: string): Promise<boolean>;
|
|
8
18
|
}
|
|
9
|
-
declare function KvAdapter(adapter: KvAdapter): KvAdapter;
|
|
10
19
|
|
|
11
|
-
interface
|
|
20
|
+
interface MongoEntityUserInput<Schema extends AnySchema> {
|
|
12
21
|
name: string;
|
|
13
|
-
adapter: KvAdapter;
|
|
14
22
|
model: Schema;
|
|
15
23
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
declare class MongoEntity<Schema extends AnySchema> {
|
|
25
|
+
readonly states: MongoEntityUserInput<Schema>;
|
|
26
|
+
private readonly collection;
|
|
27
|
+
constructor(userInput: MongoEntityUserInput<Schema>, db: Db);
|
|
28
|
+
insertOne(doc: Schema['$insert'], options?: InsertOneOptions): Promise<InsertOneResult>;
|
|
29
|
+
insertMany(docs: Schema['$insert'][], options?: BulkWriteOptions): Promise<InsertManyResult>;
|
|
30
|
+
findOne(filter: Filter<Schema['$select']>, options?: FindOptions): Promise<Schema['$select'] | null>;
|
|
31
|
+
find(filter: Filter<Schema['$select']>, options?: FindOptions): Promise<Schema['$select'][]>;
|
|
32
|
+
updateOne(filter: Filter<Schema['$select']>, update: UpdateFilter<Schema['$update']>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
33
|
+
updateMany(filter: Filter<Schema['$select']>, update: UpdateFilter<Schema['$update']>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
34
|
+
replaceOne(filter: Filter<Schema['$select']>, replacement: Schema['$select'], options?: ReplaceOptions): Promise<UpdateResult>;
|
|
35
|
+
deleteOne(filter: Filter<Schema['$select']>, options?: DeleteOptions): Promise<DeleteResult>;
|
|
36
|
+
deleteMany(filter: Filter<Schema['$select']>, options?: DeleteOptions): Promise<DeleteResult>;
|
|
37
|
+
findOneAndUpdate(filter: Filter<Schema['$select']>, update: UpdateFilter<Schema['$update']>, options?: FindOneAndUpdateOptions): Promise<Schema['$select'] | null>;
|
|
38
|
+
findOneAndDelete(filter: Filter<Schema['$select']>, options?: FindOneAndDeleteOptions): Promise<Schema['$select'] | null>;
|
|
39
|
+
findOneAndReplace(filter: Filter<Schema['$select']>, replacement: Schema['$select'], options?: FindOneAndReplaceOptions): Promise<Schema['$select'] | null>;
|
|
40
|
+
countDocuments(filter: Filter<Schema['$select']>, options?: CountDocumentsOptions): Promise<number>;
|
|
41
|
+
estimatedDocumentCount(): Promise<number>;
|
|
42
|
+
distinct<Field extends keyof Schema['$select'] & string>(field: Field, filter: Filter<Schema['$select']>, options?: DistinctOptions): Promise<Array<Schema['$select'][Field]>>;
|
|
43
|
+
aggregate(pipeline: any[], options?: AggregateOptions): AggregationCursor;
|
|
44
|
+
bulkWrite(operations: any[], options?: BulkWriteOptions): Promise<BulkWriteResult>;
|
|
45
|
+
createIndex(indexSpec: any, options?: CreateIndexesOptions): Promise<string>;
|
|
46
|
+
dropIndex(indexName: string, options?: DropIndexesOptions): Promise<void>;
|
|
26
47
|
}
|
|
27
|
-
declare function KvEntity<Schema extends AnySchema>(input: KvEntityInput<Schema>): KvEntityOutput<Schema>;
|
|
28
48
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
49
|
+
declare namespace EntityBuilder {
|
|
50
|
+
interface KvAdapter {
|
|
51
|
+
get(key: string): Promise<unknown>;
|
|
52
|
+
set(key: string, value: unknown): Promise<void>;
|
|
53
|
+
delete(key: string): Promise<void>;
|
|
54
|
+
has(key: string): Promise<boolean>;
|
|
55
|
+
}
|
|
56
|
+
interface KvInput {
|
|
57
|
+
transport: 'http';
|
|
58
|
+
adapter(): KvAdapter;
|
|
59
|
+
}
|
|
60
|
+
function kv(builderInput: KvInput): {
|
|
61
|
+
entity<Schema extends AnySchema>(entityInput: KvEntityUserInput<Schema>): KvEntity<Schema>;
|
|
62
|
+
};
|
|
63
|
+
interface MongoInput {
|
|
64
|
+
adapter(): Db;
|
|
65
|
+
transport: 'http';
|
|
66
|
+
}
|
|
67
|
+
function mongo(builderInput: MongoInput): {
|
|
68
|
+
entity<Schema extends AnySchema>(entityInput: MongoEntityUserInput<Schema>): MongoEntity<Schema>;
|
|
69
|
+
};
|
|
42
70
|
}
|
|
43
|
-
declare function MongoAdapter(adapter: MongoAdapter): MongoAdapter;
|
|
44
71
|
|
|
45
|
-
interface
|
|
46
|
-
|
|
47
|
-
adapter: MongoAdapter;
|
|
48
|
-
model: Schema;
|
|
72
|
+
interface ComposeInput {
|
|
73
|
+
entities: Array<MongoEntity<AnySchema> | KvEntity<AnySchema>>;
|
|
49
74
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
declare function compose(input: ComposeInput): {
|
|
76
|
+
readonly descriptor: {
|
|
77
|
+
entities: any[];
|
|
78
|
+
};
|
|
79
|
+
dispatch(route: string, payload: unknown): Promise<any>;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
declare class Descriptor {
|
|
83
|
+
private isExcluded;
|
|
84
|
+
private parseSchema;
|
|
85
|
+
kv(entity: KvEntity<AnySchema>): {
|
|
86
|
+
name: string;
|
|
87
|
+
platform: string;
|
|
88
|
+
methods: ({
|
|
89
|
+
name: string;
|
|
90
|
+
route: string;
|
|
91
|
+
input: {
|
|
92
|
+
type: string;
|
|
93
|
+
shape?: undefined;
|
|
94
|
+
};
|
|
95
|
+
output: any;
|
|
96
|
+
} | {
|
|
97
|
+
name: string;
|
|
98
|
+
route: string;
|
|
99
|
+
input: {
|
|
100
|
+
type: string;
|
|
101
|
+
shape: {
|
|
102
|
+
key: {
|
|
103
|
+
type: string;
|
|
104
|
+
};
|
|
105
|
+
value: any;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
output: {
|
|
109
|
+
type: string;
|
|
110
|
+
};
|
|
111
|
+
})[];
|
|
112
|
+
};
|
|
113
|
+
private buildMongoMethod;
|
|
114
|
+
mongo(entity: MongoEntity<AnySchema>): {
|
|
75
115
|
name: string;
|
|
76
|
-
|
|
77
|
-
|
|
116
|
+
platform: string;
|
|
117
|
+
methods: {
|
|
118
|
+
name: string;
|
|
119
|
+
route: string;
|
|
120
|
+
input: any;
|
|
121
|
+
output: {
|
|
122
|
+
type: string;
|
|
123
|
+
shape: {
|
|
124
|
+
acknowledged: {
|
|
125
|
+
type: string;
|
|
126
|
+
};
|
|
127
|
+
matchedCount: {
|
|
128
|
+
type: string;
|
|
129
|
+
};
|
|
130
|
+
modifiedCount: {
|
|
131
|
+
type: string;
|
|
132
|
+
};
|
|
133
|
+
upsertedCount: {
|
|
134
|
+
type: string;
|
|
135
|
+
};
|
|
136
|
+
upsertedId: {
|
|
137
|
+
type: string;
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
} | {
|
|
141
|
+
type: string;
|
|
142
|
+
shape: {
|
|
143
|
+
acknowledged: {
|
|
144
|
+
type: string;
|
|
145
|
+
};
|
|
146
|
+
insertedId: {
|
|
147
|
+
type: string;
|
|
148
|
+
};
|
|
149
|
+
insertedCount?: undefined;
|
|
150
|
+
insertedIds?: undefined;
|
|
151
|
+
matchedCount?: undefined;
|
|
152
|
+
modifiedCount?: undefined;
|
|
153
|
+
upsertedCount?: undefined;
|
|
154
|
+
upsertedId?: undefined;
|
|
155
|
+
deletedCount?: undefined;
|
|
156
|
+
};
|
|
157
|
+
items?: undefined;
|
|
158
|
+
element?: undefined;
|
|
159
|
+
} | {
|
|
160
|
+
type: string;
|
|
161
|
+
shape: {
|
|
162
|
+
acknowledged: {
|
|
163
|
+
type: string;
|
|
164
|
+
};
|
|
165
|
+
insertedCount: {
|
|
166
|
+
type: string;
|
|
167
|
+
};
|
|
168
|
+
insertedIds: {
|
|
169
|
+
type: string;
|
|
170
|
+
};
|
|
171
|
+
insertedId?: undefined;
|
|
172
|
+
matchedCount?: undefined;
|
|
173
|
+
modifiedCount?: undefined;
|
|
174
|
+
upsertedCount?: undefined;
|
|
175
|
+
upsertedId?: undefined;
|
|
176
|
+
deletedCount?: undefined;
|
|
177
|
+
};
|
|
178
|
+
items?: undefined;
|
|
179
|
+
element?: undefined;
|
|
180
|
+
} | {
|
|
181
|
+
type: string;
|
|
182
|
+
items: any[];
|
|
183
|
+
shape?: undefined;
|
|
184
|
+
element?: undefined;
|
|
185
|
+
} | {
|
|
186
|
+
type: string;
|
|
187
|
+
element: any;
|
|
188
|
+
shape?: undefined;
|
|
189
|
+
items?: undefined;
|
|
190
|
+
} | {
|
|
191
|
+
type: string;
|
|
192
|
+
shape: {
|
|
193
|
+
acknowledged: {
|
|
194
|
+
type: string;
|
|
195
|
+
};
|
|
196
|
+
matchedCount: {
|
|
197
|
+
type: string;
|
|
198
|
+
};
|
|
199
|
+
modifiedCount: {
|
|
200
|
+
type: string;
|
|
201
|
+
};
|
|
202
|
+
upsertedCount: {
|
|
203
|
+
type: string;
|
|
204
|
+
};
|
|
205
|
+
upsertedId: {
|
|
206
|
+
type: string;
|
|
207
|
+
};
|
|
208
|
+
insertedId?: undefined;
|
|
209
|
+
insertedCount?: undefined;
|
|
210
|
+
insertedIds?: undefined;
|
|
211
|
+
deletedCount?: undefined;
|
|
212
|
+
};
|
|
213
|
+
items?: undefined;
|
|
214
|
+
element?: undefined;
|
|
215
|
+
} | {
|
|
216
|
+
type: string;
|
|
217
|
+
items: any[];
|
|
218
|
+
shape?: undefined;
|
|
219
|
+
element?: undefined;
|
|
220
|
+
} | {
|
|
221
|
+
type: string;
|
|
222
|
+
shape: {
|
|
223
|
+
acknowledged: {
|
|
224
|
+
type: string;
|
|
225
|
+
};
|
|
226
|
+
deletedCount: {
|
|
227
|
+
type: string;
|
|
228
|
+
};
|
|
229
|
+
insertedId?: undefined;
|
|
230
|
+
insertedCount?: undefined;
|
|
231
|
+
insertedIds?: undefined;
|
|
232
|
+
matchedCount?: undefined;
|
|
233
|
+
modifiedCount?: undefined;
|
|
234
|
+
upsertedCount?: undefined;
|
|
235
|
+
upsertedId?: undefined;
|
|
236
|
+
};
|
|
237
|
+
items?: undefined;
|
|
238
|
+
element?: undefined;
|
|
239
|
+
} | {
|
|
240
|
+
type: string;
|
|
241
|
+
shape?: undefined;
|
|
242
|
+
items?: undefined;
|
|
243
|
+
element?: undefined;
|
|
244
|
+
};
|
|
245
|
+
}[];
|
|
78
246
|
};
|
|
79
247
|
}
|
|
80
|
-
declare function MongoEntity<Schema extends AnySchema>(input: MongoEntityInput<Schema>): MongoEntityOutput<Schema>;
|
|
81
248
|
|
|
82
|
-
|
|
249
|
+
type Composed = ReturnType<typeof compose>;
|
|
250
|
+
declare function make(composed: Composed): {
|
|
251
|
+
listen(port: number): http.Server<typeof IncomingMessage, typeof ServerResponse>;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
export { type ComposeInput, Descriptor, EntityBuilder, KvEntity, type KvEntityUserInput, MongoEntity, type MongoEntityUserInput, compose, make };
|
package/dist/index.js
CHANGED
|
@@ -1,88 +1,380 @@
|
|
|
1
|
-
// src/kv
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// src/entity/platforms/kv.ts
|
|
2
|
+
var KvEntity = class {
|
|
3
|
+
state;
|
|
4
|
+
adapter;
|
|
5
|
+
constructor(userProvided, internal) {
|
|
6
|
+
this.state = userProvided;
|
|
7
|
+
this.adapter = internal;
|
|
8
|
+
}
|
|
9
|
+
async get(key) {
|
|
10
|
+
const formattedKey = `${this.state.name}:${key}`;
|
|
11
|
+
const raw = await this.adapter.get(formattedKey);
|
|
12
|
+
return raw;
|
|
13
|
+
}
|
|
14
|
+
async set(key, value) {
|
|
15
|
+
const formattedKey = `${this.state.name}:${key}`;
|
|
16
|
+
await this.adapter.set(formattedKey, value);
|
|
17
|
+
}
|
|
18
|
+
async delete(key) {
|
|
19
|
+
const formattedKey = `${this.state.name}:${key}`;
|
|
20
|
+
await this.adapter.delete(formattedKey);
|
|
21
|
+
}
|
|
22
|
+
async has(key) {
|
|
23
|
+
const formattedKey = `${this.state.name}:${key}`;
|
|
24
|
+
return this.adapter.has(formattedKey);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/entity/platforms/mongo.ts
|
|
29
|
+
var MongoEntity = class {
|
|
30
|
+
states;
|
|
31
|
+
collection;
|
|
32
|
+
constructor(userInput, db) {
|
|
33
|
+
this.states = userInput;
|
|
34
|
+
this.collection = db.collection(userInput.name);
|
|
35
|
+
}
|
|
36
|
+
async insertOne(doc, options) {
|
|
37
|
+
return this.collection.insertOne(doc, options);
|
|
38
|
+
}
|
|
39
|
+
async insertMany(docs, options) {
|
|
40
|
+
return this.collection.insertMany(docs, options);
|
|
41
|
+
}
|
|
42
|
+
async findOne(filter, options) {
|
|
43
|
+
return this.collection.findOne(filter, options);
|
|
44
|
+
}
|
|
45
|
+
async find(filter, options) {
|
|
46
|
+
return this.collection.find(filter, options).toArray();
|
|
47
|
+
}
|
|
48
|
+
async updateOne(filter, update, options) {
|
|
49
|
+
return this.collection.updateOne(filter, update, options);
|
|
50
|
+
}
|
|
51
|
+
async updateMany(filter, update, options) {
|
|
52
|
+
return this.collection.updateMany(filter, update, options);
|
|
53
|
+
}
|
|
54
|
+
async replaceOne(filter, replacement, options) {
|
|
55
|
+
return this.collection.replaceOne(filter, replacement, options);
|
|
56
|
+
}
|
|
57
|
+
async deleteOne(filter, options) {
|
|
58
|
+
return this.collection.deleteOne(filter, options);
|
|
59
|
+
}
|
|
60
|
+
async deleteMany(filter, options) {
|
|
61
|
+
return this.collection.deleteMany(filter, options);
|
|
62
|
+
}
|
|
63
|
+
async findOneAndUpdate(filter, update, options) {
|
|
64
|
+
return this.collection.findOneAndUpdate(filter, update, options);
|
|
65
|
+
}
|
|
66
|
+
async findOneAndDelete(filter, options) {
|
|
67
|
+
return this.collection.findOneAndDelete(filter, options);
|
|
68
|
+
}
|
|
69
|
+
async findOneAndReplace(filter, replacement, options) {
|
|
70
|
+
return this.collection.findOneAndReplace(filter, replacement, options);
|
|
71
|
+
}
|
|
72
|
+
async countDocuments(filter, options) {
|
|
73
|
+
return this.collection.countDocuments(filter, options);
|
|
74
|
+
}
|
|
75
|
+
async estimatedDocumentCount() {
|
|
76
|
+
return this.collection.estimatedDocumentCount();
|
|
77
|
+
}
|
|
78
|
+
async distinct(field, filter, options) {
|
|
79
|
+
return this.collection.distinct(field, filter, options);
|
|
80
|
+
}
|
|
81
|
+
aggregate(pipeline, options) {
|
|
82
|
+
return this.collection.aggregate(pipeline, options);
|
|
83
|
+
}
|
|
84
|
+
async bulkWrite(operations, options) {
|
|
85
|
+
return this.collection.bulkWrite(operations, options);
|
|
86
|
+
}
|
|
87
|
+
async createIndex(indexSpec, options) {
|
|
88
|
+
return this.collection.createIndex(indexSpec, options);
|
|
89
|
+
}
|
|
90
|
+
async dropIndex(indexName, options) {
|
|
91
|
+
return this.collection.dropIndex(indexName, options);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
5
94
|
|
|
6
|
-
// src/
|
|
7
|
-
|
|
8
|
-
|
|
95
|
+
// src/entity/builder.ts
|
|
96
|
+
var EntityBuilder;
|
|
97
|
+
((EntityBuilder2) => {
|
|
98
|
+
function kv(builderInput) {
|
|
99
|
+
const adapter = builderInput.adapter();
|
|
100
|
+
const result = {
|
|
101
|
+
entity(entityInput) {
|
|
102
|
+
return new KvEntity(entityInput, adapter);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
EntityBuilder2.kv = kv;
|
|
108
|
+
function mongo(builderInput) {
|
|
109
|
+
const db = builderInput.adapter();
|
|
110
|
+
const result = {
|
|
111
|
+
entity(entityInput) {
|
|
112
|
+
return new MongoEntity(entityInput, db);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
EntityBuilder2.mongo = mongo;
|
|
118
|
+
})(EntityBuilder || (EntityBuilder = {}));
|
|
119
|
+
|
|
120
|
+
// src/organize/descriptor.ts
|
|
121
|
+
var Descriptor = class {
|
|
122
|
+
isExcluded(schema, slot) {
|
|
123
|
+
const accessors = schema.state.accessors ?? {};
|
|
124
|
+
if (slot === "select") return !!accessors.hidden;
|
|
125
|
+
if (slot === "insert") return accessors.readonlyValue !== void 0 || !!accessors.readonlyFn;
|
|
126
|
+
return accessors.readonlyValue !== void 0 || !!accessors.readonlyFn || !!accessors.locked;
|
|
127
|
+
}
|
|
128
|
+
parseSchema(schema, slot) {
|
|
129
|
+
const state = schema.state;
|
|
130
|
+
if (state.type === "object") {
|
|
131
|
+
const shape = state.typeMeta.objectShape ?? {};
|
|
132
|
+
const fields = {};
|
|
133
|
+
for (const key in shape) {
|
|
134
|
+
if (this.isExcluded(shape[key], slot)) continue;
|
|
135
|
+
fields[key] = this.parseSchema(shape[key], slot);
|
|
136
|
+
}
|
|
137
|
+
return { type: "object", shape: fields };
|
|
138
|
+
}
|
|
139
|
+
if (state.type === "array") {
|
|
140
|
+
return { type: "array", element: this.parseSchema(state.typeMeta.arrayElement, slot) };
|
|
141
|
+
}
|
|
142
|
+
if (state.type === "tuple") {
|
|
143
|
+
return { type: "tuple", items: (state.typeMeta.tupleItems ?? []).map((s) => this.parseSchema(s, slot)) };
|
|
144
|
+
}
|
|
145
|
+
if (state.type === "union") {
|
|
146
|
+
return { type: "union", items: (state.typeMeta.unionItems ?? []).map((s) => this.parseSchema(s, slot)) };
|
|
147
|
+
}
|
|
148
|
+
if (state.type === "record") {
|
|
149
|
+
return { type: "record", element: this.parseSchema(state.typeMeta.recordElement, slot) };
|
|
150
|
+
}
|
|
151
|
+
if (state.type === "literals") {
|
|
152
|
+
return { type: "literals", values: state.typeMeta.literalValues };
|
|
153
|
+
}
|
|
154
|
+
return { type: state.type };
|
|
155
|
+
}
|
|
156
|
+
kv(entity) {
|
|
157
|
+
const name = entity.state.name;
|
|
158
|
+
const model = entity.state.model;
|
|
159
|
+
return {
|
|
160
|
+
name,
|
|
161
|
+
platform: "kv",
|
|
162
|
+
methods: [
|
|
163
|
+
{ name: "get", route: `${name}.kv.get`, input: { type: "string" }, output: this.parseSchema(model, "select") },
|
|
164
|
+
{ name: "set", route: `${name}.kv.set`, input: { type: "object", shape: { key: { type: "string" }, value: this.parseSchema(model, "insert") } }, output: { type: "null" } },
|
|
165
|
+
{ name: "delete", route: `${name}.kv.delete`, input: { type: "string" }, output: { type: "null" } },
|
|
166
|
+
{ name: "has", route: `${name}.kv.has`, input: { type: "string" }, output: { type: "boolean" } }
|
|
167
|
+
]
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
buildMongoMethod(model, methodName) {
|
|
171
|
+
if (methodName === "insertOne") {
|
|
172
|
+
return { input: this.parseSchema(model, "insert"), output: { type: "object", shape: { acknowledged: { type: "boolean" }, insertedId: { type: "unknown" } } } };
|
|
173
|
+
}
|
|
174
|
+
if (methodName === "insertMany") {
|
|
175
|
+
return {
|
|
176
|
+
input: { type: "array", element: this.parseSchema(model, "insert") },
|
|
177
|
+
output: { type: "object", shape: { acknowledged: { type: "boolean" }, insertedCount: { type: "number" }, insertedIds: { type: "unknown" } } }
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
if (methodName === "findOne") {
|
|
181
|
+
return { input: this.parseSchema(model, "select"), output: { type: "union", items: [this.parseSchema(model, "select"), { type: "null" }] } };
|
|
182
|
+
}
|
|
183
|
+
if (methodName === "find") {
|
|
184
|
+
return { input: this.parseSchema(model, "select"), output: { type: "array", element: this.parseSchema(model, "select") } };
|
|
185
|
+
}
|
|
186
|
+
if (methodName === "updateOne" || methodName === "updateMany") {
|
|
187
|
+
return {
|
|
188
|
+
input: { type: "object", shape: { filter: this.parseSchema(model, "select"), update: this.parseSchema(model, "update") } },
|
|
189
|
+
output: {
|
|
190
|
+
type: "object",
|
|
191
|
+
shape: {
|
|
192
|
+
acknowledged: { type: "boolean" },
|
|
193
|
+
matchedCount: { type: "number" },
|
|
194
|
+
modifiedCount: { type: "number" },
|
|
195
|
+
upsertedCount: { type: "number" },
|
|
196
|
+
upsertedId: { type: "unknown" }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (methodName === "replaceOne" || methodName === "findOneAndReplace") {
|
|
202
|
+
const updateResultShape = {
|
|
203
|
+
type: "object",
|
|
204
|
+
shape: { acknowledged: { type: "boolean" }, matchedCount: { type: "number" }, modifiedCount: { type: "number" }, upsertedCount: { type: "number" }, upsertedId: { type: "unknown" } }
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
input: { type: "object", shape: { filter: this.parseSchema(model, "select"), replacement: this.parseSchema(model, "select") } },
|
|
208
|
+
output: methodName === "replaceOne" ? updateResultShape : { type: "union", items: [this.parseSchema(model, "select"), { type: "null" }] }
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (methodName === "deleteOne" || methodName === "deleteMany") {
|
|
212
|
+
return { input: this.parseSchema(model, "select"), output: { type: "object", shape: { acknowledged: { type: "boolean" }, deletedCount: { type: "number" } } } };
|
|
213
|
+
}
|
|
214
|
+
if (methodName === "findOneAndUpdate") {
|
|
215
|
+
return {
|
|
216
|
+
input: { type: "object", shape: { filter: this.parseSchema(model, "select"), update: this.parseSchema(model, "update") } },
|
|
217
|
+
output: { type: "union", items: [this.parseSchema(model, "select"), { type: "null" }] }
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
if (methodName === "findOneAndDelete") {
|
|
221
|
+
return { input: this.parseSchema(model, "select"), output: { type: "union", items: [this.parseSchema(model, "select"), { type: "null" }] } };
|
|
222
|
+
}
|
|
223
|
+
if (methodName === "countDocuments") {
|
|
224
|
+
return { input: this.parseSchema(model, "select"), output: { type: "number" } };
|
|
225
|
+
}
|
|
226
|
+
if (methodName === "estimatedDocumentCount") {
|
|
227
|
+
return { input: { type: "null" }, output: { type: "number" } };
|
|
228
|
+
}
|
|
229
|
+
if (methodName === "distinct") {
|
|
230
|
+
return { input: { type: "object", shape: { field: { type: "string" }, filter: this.parseSchema(model, "select") } }, output: { type: "unknown" } };
|
|
231
|
+
}
|
|
232
|
+
if (methodName === "createIndex") {
|
|
233
|
+
return { input: { type: "unknown" }, output: { type: "string" } };
|
|
234
|
+
}
|
|
235
|
+
if (methodName === "dropIndex") {
|
|
236
|
+
return { input: { type: "string" }, output: { type: "null" } };
|
|
237
|
+
}
|
|
238
|
+
return { input: { type: "unknown" }, output: { type: "unknown" } };
|
|
239
|
+
}
|
|
240
|
+
mongo(entity) {
|
|
241
|
+
const name = entity.states.name;
|
|
242
|
+
const model = entity.states.model;
|
|
243
|
+
const proto = Object.getPrototypeOf(entity);
|
|
244
|
+
const methods = [];
|
|
245
|
+
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
246
|
+
if (key === "constructor") continue;
|
|
247
|
+
const shape = this.buildMongoMethod(model, key);
|
|
248
|
+
methods.push({ name: key, route: `${name}.mongo.${key}`, input: shape.input, output: shape.output });
|
|
249
|
+
}
|
|
250
|
+
return { name, platform: "mongo", methods };
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// src/organize/compose.ts
|
|
255
|
+
function compose(input) {
|
|
256
|
+
const descriptors = [];
|
|
257
|
+
const routes = /* @__PURE__ */ new Map();
|
|
258
|
+
const des = new Descriptor();
|
|
259
|
+
for (const entity of input.entities) {
|
|
260
|
+
if (entity instanceof MongoEntity) {
|
|
261
|
+
const descriptor = des.mongo(entity);
|
|
262
|
+
descriptors.push(descriptor);
|
|
263
|
+
for (const method of descriptor.methods) {
|
|
264
|
+
routes.set(method.route, { entity, methodName: method.name });
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (entity instanceof KvEntity) {
|
|
268
|
+
const descriptor = des.kv(entity);
|
|
269
|
+
descriptors.push(descriptor);
|
|
270
|
+
for (const method of descriptor.methods) {
|
|
271
|
+
routes.set(method.route, { entity, methodName: method.name });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
9
275
|
return {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const raw = await adapter.get(formattedKey);
|
|
13
|
-
return input.model.parse(raw);
|
|
14
|
-
},
|
|
15
|
-
async set(key, value) {
|
|
16
|
-
const formattedKey = `${input.name}:${key}`;
|
|
17
|
-
const validated = input.model.parse(value);
|
|
18
|
-
await adapter.set(formattedKey, validated);
|
|
276
|
+
get descriptor() {
|
|
277
|
+
return { entities: descriptors };
|
|
19
278
|
},
|
|
20
|
-
async
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
return
|
|
27
|
-
},
|
|
28
|
-
state: {
|
|
29
|
-
adapter,
|
|
30
|
-
model: input.model,
|
|
31
|
-
name: input.name
|
|
279
|
+
async dispatch(route, payload) {
|
|
280
|
+
const target = routes.get(route);
|
|
281
|
+
if (target === void 0) {
|
|
282
|
+
throw new Error(`no method registered for route "${route}"`);
|
|
283
|
+
}
|
|
284
|
+
const fn = target.entity[target.methodName];
|
|
285
|
+
return fn.call(target.entity, payload);
|
|
32
286
|
}
|
|
33
287
|
};
|
|
34
288
|
}
|
|
35
289
|
|
|
36
|
-
// src/
|
|
37
|
-
|
|
38
|
-
|
|
290
|
+
// src/organize/make.ts
|
|
291
|
+
import { createServer } from "http";
|
|
292
|
+
async function toWebRequest(req) {
|
|
293
|
+
const url = `http://${req.headers.host}${req.url}`;
|
|
294
|
+
const headers = new Headers();
|
|
295
|
+
for (const key in req.headers) {
|
|
296
|
+
const value = req.headers[key];
|
|
297
|
+
if (typeof value === "string") {
|
|
298
|
+
headers.set(key, value);
|
|
299
|
+
}
|
|
300
|
+
if (Array.isArray(value)) {
|
|
301
|
+
headers.set(key, value.join(", "));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (req.method === "GET" || req.method === "HEAD") {
|
|
305
|
+
return new Request(url, { method: req.method, headers });
|
|
306
|
+
}
|
|
307
|
+
const chunks = [];
|
|
308
|
+
for await (const chunk of req) {
|
|
309
|
+
chunks.push(chunk);
|
|
310
|
+
}
|
|
311
|
+
const body = Buffer.concat(chunks);
|
|
312
|
+
return new Request(url, { method: req.method, headers, body });
|
|
39
313
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
314
|
+
async function writeWebResponse(webResponse, res) {
|
|
315
|
+
res.statusCode = webResponse.status;
|
|
316
|
+
webResponse.headers.forEach((value, key) => {
|
|
317
|
+
res.setHeader(key, value);
|
|
318
|
+
});
|
|
319
|
+
if (webResponse.body === null) {
|
|
320
|
+
res.end();
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const reader = webResponse.body.getReader();
|
|
324
|
+
while (true) {
|
|
325
|
+
const next = await reader.read();
|
|
326
|
+
if (next.done) {
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
res.write(next.value);
|
|
330
|
+
}
|
|
331
|
+
res.end();
|
|
332
|
+
}
|
|
333
|
+
async function handle(request, composed) {
|
|
334
|
+
const url = new URL(request.url);
|
|
335
|
+
if (url.pathname === "/meta") {
|
|
336
|
+
return Response.json(composed.descriptor);
|
|
337
|
+
}
|
|
338
|
+
const route = request.headers.get("x-amx-id");
|
|
339
|
+
if (route === null) {
|
|
340
|
+
return Response.json({ data: null, errors: null });
|
|
341
|
+
}
|
|
342
|
+
let payload;
|
|
343
|
+
try {
|
|
344
|
+
payload = await request.json();
|
|
345
|
+
} catch {
|
|
346
|
+
payload = void 0;
|
|
347
|
+
}
|
|
348
|
+
try {
|
|
349
|
+
const data = await composed.dispatch(route, payload);
|
|
350
|
+
return Response.json({ data, errors: null });
|
|
351
|
+
} catch (error) {
|
|
352
|
+
let message = "unknown error";
|
|
353
|
+
if (error instanceof Error) {
|
|
354
|
+
message = error.message;
|
|
355
|
+
}
|
|
356
|
+
return Response.json({ data: null, errors: message }, { status: 400 });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function make(composed) {
|
|
44
360
|
return {
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
async findOne(filter) {
|
|
56
|
-
const raw = await collection.findOne(filter);
|
|
57
|
-
return raw === null ? null : input.model.parse(raw);
|
|
58
|
-
},
|
|
59
|
-
async find(filter) {
|
|
60
|
-
const raw = await collection.find(filter);
|
|
61
|
-
return raw.map((r) => input.model.parse(r));
|
|
62
|
-
},
|
|
63
|
-
async updateOne(filter, update) {
|
|
64
|
-
const result = await collection.updateOne(filter, update);
|
|
65
|
-
return { matchedCount: result.matchedCount, modifiedCount: result.modifiedCount };
|
|
66
|
-
},
|
|
67
|
-
async updateMany(filter, update) {
|
|
68
|
-
const result = await collection.updateMany(filter, update);
|
|
69
|
-
return { matchedCount: result.matchedCount, modifiedCount: result.modifiedCount };
|
|
70
|
-
},
|
|
71
|
-
async deleteOne(filter) {
|
|
72
|
-
const result = await collection.deleteOne(filter);
|
|
73
|
-
return { deletedCount: result.deletedCount };
|
|
74
|
-
},
|
|
75
|
-
async deleteMany(filter) {
|
|
76
|
-
const result = await collection.deleteMany(filter);
|
|
77
|
-
return { deletedCount: result.deletedCount };
|
|
78
|
-
},
|
|
79
|
-
countDocuments: (filter) => collection.countDocuments(filter),
|
|
80
|
-
state: { name: input.name, adapter: input.adapter, model: input.model }
|
|
361
|
+
listen(port) {
|
|
362
|
+
const server = createServer((req, res) => {
|
|
363
|
+
toWebRequest(req).then((request) => handle(request, composed)).then((response) => writeWebResponse(response, res)).catch((error) => {
|
|
364
|
+
res.statusCode = 500;
|
|
365
|
+
res.end("internal error");
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
server.listen(port);
|
|
369
|
+
return server;
|
|
370
|
+
}
|
|
81
371
|
};
|
|
82
372
|
}
|
|
83
373
|
export {
|
|
84
|
-
|
|
374
|
+
Descriptor,
|
|
375
|
+
EntityBuilder,
|
|
85
376
|
KvEntity,
|
|
86
|
-
|
|
87
|
-
|
|
377
|
+
MongoEntity,
|
|
378
|
+
compose,
|
|
379
|
+
make
|
|
88
380
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aromix/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "The Core Package For Aromix",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,12 +41,19 @@
|
|
|
41
41
|
"typecheck": "tsc --noEmit"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
|
-
"@aromix/validator": "^0.
|
|
44
|
+
"@aromix/validator": "^0.3.0",
|
|
45
|
+
"mongodb": "^7.3.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
|
-
"@aromix/validator": "^0.
|
|
48
|
+
"@aromix/validator": "^0.3.0",
|
|
48
49
|
"@types/node": "^22.10.2",
|
|
50
|
+
"mongodb": "^7.3.0",
|
|
49
51
|
"tsup": "^8.3.5",
|
|
50
52
|
"typescript": "^5.7.2"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"mongodb": {
|
|
56
|
+
"optional": true
|
|
57
|
+
}
|
|
51
58
|
}
|
|
52
59
|
}
|