@neupgroup/mapper 1.2.2 → 1.2.4
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/README.md +3 -704
- package/dist/adapters/api-adapter.d.ts +45 -0
- package/dist/adapters/api-adapter.js +170 -0
- package/dist/adapters/index.d.ts +34 -0
- package/dist/adapters/index.js +91 -0
- package/dist/adapters/mongodb-adapter.d.ts +56 -0
- package/dist/adapters/mongodb-adapter.js +227 -0
- package/dist/adapters/mysql-adapter.d.ts +38 -0
- package/dist/adapters/mysql-adapter.js +166 -0
- package/dist/adapters/postgres-adapter.d.ts +52 -0
- package/dist/adapters/postgres-adapter.js +204 -0
- package/dist/config.d.ts +2 -2
- package/dist/config.js +1 -1
- package/dist/connector.d.ts +57 -0
- package/dist/connector.js +114 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.js +50 -0
- package/dist/fluent-mapper.d.ts +30 -2
- package/dist/fluent-mapper.js +157 -5
- package/dist/index.d.ts +53 -13
- package/dist/index.js +188 -69
- package/dist/mapper.d.ts +2 -1
- package/dist/mapper.js +5 -1
- package/dist/orm/index.d.ts +3 -3
- package/dist/usage_example.d.ts +1 -0
- package/dist/usage_example.js +37 -0
- package/dist/usage_example_v2.d.ts +1 -0
- package/dist/usage_example_v2.js +19 -0
- package/package.json +23 -23
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AdapterMissingError, ConnectionExistingError, ConnectionUnknownError, DocumentMissingIdError, SchemaExistingError, SchemaMissingError, UpdatePayloadMissingError, } from './errors.js';
|
|
1
2
|
class AdapterRegistry {
|
|
2
3
|
constructor() {
|
|
3
4
|
this.adaptersByConnection = new Map();
|
|
@@ -27,20 +28,20 @@ export class Connections {
|
|
|
27
28
|
}
|
|
28
29
|
create(name, type) {
|
|
29
30
|
if (this.connections.has(name)) {
|
|
30
|
-
throw new
|
|
31
|
+
throw new ConnectionExistingError(name);
|
|
31
32
|
}
|
|
32
33
|
return new ConnectionBuilder(this, name, type);
|
|
33
34
|
}
|
|
34
35
|
register(config) {
|
|
35
36
|
if (this.connections.has(config.name)) {
|
|
36
|
-
throw new
|
|
37
|
+
throw new ConnectionExistingError(config.name);
|
|
37
38
|
}
|
|
38
39
|
this.connections.set(config.name, config);
|
|
39
40
|
return this;
|
|
40
41
|
}
|
|
41
42
|
attachAdapter(name, adapter) {
|
|
42
43
|
if (!this.connections.has(name)) {
|
|
43
|
-
throw new
|
|
44
|
+
throw new ConnectionUnknownError('attach adapter', name);
|
|
44
45
|
}
|
|
45
46
|
this.adapters.attach(name, adapter);
|
|
46
47
|
return this;
|
|
@@ -55,22 +56,69 @@ export class Connections {
|
|
|
55
56
|
return Array.from(this.connections.values());
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
|
-
function
|
|
59
|
+
function parseFieldRule(field, rule) {
|
|
60
|
+
if (Array.isArray(rule)) {
|
|
61
|
+
// Enum or options
|
|
62
|
+
field.enumValues = rule;
|
|
63
|
+
field.type = 'string'; // Usually enums are strings
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (typeof rule !== 'string')
|
|
67
|
+
return;
|
|
68
|
+
if (rule === 'auto-increment')
|
|
69
|
+
field.autoIncrement = true;
|
|
70
|
+
if (rule === 'unique')
|
|
71
|
+
field.isUnique = true;
|
|
72
|
+
if (rule.startsWith('max.')) { /* Validation ref */ }
|
|
73
|
+
if (rule === 'enum') { /* marker */ }
|
|
74
|
+
if (rule === 'default_current_datetime' || rule === 'default.currentDatetime') {
|
|
75
|
+
field.defaultValue = 'NOW()';
|
|
76
|
+
}
|
|
77
|
+
if (rule.startsWith('default.value')) {
|
|
78
|
+
// Handling 'default.value', 'actualValue' pattern if passed as array items or just parsing string?
|
|
79
|
+
// User said: 'default.value', 'value'
|
|
80
|
+
// This parser handles single string rules from the array.
|
|
81
|
+
// We might need to look ahead in the loop for values, but usually 'value' is separate.
|
|
82
|
+
// For now assuming the user provided array is flat: ['string', 'default.value', 'foo']
|
|
83
|
+
// But user example: 'gender' : ['string', 'max.10', 'enum', ['option1', 'option2']];
|
|
84
|
+
}
|
|
85
|
+
// Foreign key: 'foreignKey.tableName.fieldName'
|
|
86
|
+
if (rule.startsWith('foreignKey.')) {
|
|
87
|
+
field.isForeignKey = true;
|
|
88
|
+
field.foreignRef = rule.replace('foreignKey.', '');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function parseDescriptorStructure(struct) {
|
|
59
92
|
let allowUndefinedFields = false;
|
|
60
93
|
const fields = [];
|
|
61
94
|
for (const [key, descriptor] of Object.entries(struct)) {
|
|
62
95
|
if (key === '?field') {
|
|
63
|
-
// Presence of '?field' enables accepting fields not defined in the schema
|
|
64
96
|
allowUndefinedFields = true;
|
|
65
97
|
continue;
|
|
66
98
|
}
|
|
67
|
-
const tokens = descriptor.split(/\s+/).map(t => t.trim().toLowerCase()).filter(Boolean);
|
|
68
99
|
const field = {
|
|
69
100
|
name: key,
|
|
70
|
-
type:
|
|
71
|
-
|
|
72
|
-
autoIncrement: tokens.includes('auto_increment') || tokens.includes('autoincrement'),
|
|
101
|
+
type: 'string', // default
|
|
102
|
+
config: Array.isArray(descriptor) ? descriptor : [descriptor]
|
|
73
103
|
};
|
|
104
|
+
const rules = Array.isArray(descriptor) ? descriptor : descriptor.split(/\s+/);
|
|
105
|
+
// First item is typically type if strictly following example ['integer', ...]
|
|
106
|
+
if (rules.length > 0 && typeof rules[0] === 'string') {
|
|
107
|
+
const t = rules[0].toLowerCase();
|
|
108
|
+
if (['string', 'integer', 'number', 'boolean', 'datetime', 'date', 'int'].includes(t)) {
|
|
109
|
+
field.type = (t === 'integer' ? 'int' : t === 'datetime' ? 'date' : t);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
for (let i = 0; i < rules.length; i++) {
|
|
113
|
+
const rule = rules[i];
|
|
114
|
+
if (rule === 'default.value' && i + 1 < rules.length) {
|
|
115
|
+
field.defaultValue = rules[i + 1];
|
|
116
|
+
i++; // Skip next
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
parseFieldRule(field, rule);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
74
122
|
fields.push(field);
|
|
75
123
|
}
|
|
76
124
|
return { fields, allowUndefinedFields };
|
|
@@ -81,12 +129,29 @@ class SchemaBuilder {
|
|
|
81
129
|
this.name = name;
|
|
82
130
|
this.fields = [];
|
|
83
131
|
this.allowUndefinedFields = false;
|
|
132
|
+
this.deleteType = 'hardDelete';
|
|
133
|
+
this.massDeleteAllowed = true;
|
|
134
|
+
this.massEditAllowed = true;
|
|
84
135
|
}
|
|
85
136
|
use(options) {
|
|
86
137
|
this.connectionName = options.connection;
|
|
87
138
|
this.collectionName = options.collection;
|
|
88
139
|
return this;
|
|
89
140
|
}
|
|
141
|
+
// New configuration methods
|
|
142
|
+
setOptions(options) {
|
|
143
|
+
if (options.insertableFields)
|
|
144
|
+
this.insertableFields = options.insertableFields;
|
|
145
|
+
if (options.updatableFields)
|
|
146
|
+
this.updatableFields = options.updatableFields;
|
|
147
|
+
if (options.deleteType)
|
|
148
|
+
this.deleteType = options.deleteType;
|
|
149
|
+
if (options.massDeleteAllowed !== undefined)
|
|
150
|
+
this.massDeleteAllowed = options.massDeleteAllowed;
|
|
151
|
+
if (options.massEditAllowed !== undefined)
|
|
152
|
+
this.massEditAllowed = options.massEditAllowed;
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
90
155
|
setStructure(structure) {
|
|
91
156
|
if (Array.isArray(structure)) {
|
|
92
157
|
this.fields = structure;
|
|
@@ -99,14 +164,25 @@ class SchemaBuilder {
|
|
|
99
164
|
}
|
|
100
165
|
// Finalize schema registration
|
|
101
166
|
if (!this.connectionName || !this.collectionName) {
|
|
102
|
-
|
|
167
|
+
// Fallback or error? User might set connection later or globally?
|
|
168
|
+
// For now, allow lazy registration if connection generic, but the prompt implies explicit definition flow.
|
|
169
|
+
// If not set, we might throw or wait. The original threw error.
|
|
170
|
+
// But user provided: "Mapper.schemas('name').get()..." -> implies definition might happen elsewhere or connection is optional if already defined.
|
|
103
171
|
}
|
|
172
|
+
const fieldsMap = new Map();
|
|
173
|
+
this.fields.forEach(f => fieldsMap.set(f.name, f));
|
|
104
174
|
this.manager.register({
|
|
105
175
|
name: this.name,
|
|
106
|
-
connectionName: this.connectionName,
|
|
176
|
+
connectionName: this.connectionName, // Assuming set
|
|
107
177
|
collectionName: this.collectionName,
|
|
108
178
|
fields: this.fields,
|
|
179
|
+
fieldsMap,
|
|
109
180
|
allowUndefinedFields: this.allowUndefinedFields,
|
|
181
|
+
insertableFields: this.insertableFields,
|
|
182
|
+
updatableFields: this.updatableFields,
|
|
183
|
+
deleteType: this.deleteType,
|
|
184
|
+
massDeleteAllowed: this.massDeleteAllowed,
|
|
185
|
+
massEditAllowed: this.massEditAllowed
|
|
110
186
|
});
|
|
111
187
|
return this.manager;
|
|
112
188
|
}
|
|
@@ -118,6 +194,28 @@ class SchemaQuery {
|
|
|
118
194
|
this.filters = [];
|
|
119
195
|
this.rawWhere = null;
|
|
120
196
|
this.pendingUpdate = null;
|
|
197
|
+
this.cachedAdapter = null;
|
|
198
|
+
this._limit = null;
|
|
199
|
+
this._offset = null;
|
|
200
|
+
this.cachedFieldNames = this.def.fields.map(f => f.name);
|
|
201
|
+
this.allowedFields = new Set(this.cachedFieldNames);
|
|
202
|
+
}
|
|
203
|
+
limit(n) {
|
|
204
|
+
this._limit = n;
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
offset(n) {
|
|
208
|
+
this._offset = n;
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
selectFields(fields) {
|
|
212
|
+
// Validate fields exist?
|
|
213
|
+
// For now just restrict cachedFieldNames to this subset for the query options
|
|
214
|
+
// But cachedFieldNames is used by other things?
|
|
215
|
+
// Clone?
|
|
216
|
+
// Let's store a projection override.
|
|
217
|
+
this.cachedFieldNames = fields;
|
|
218
|
+
return this;
|
|
121
219
|
}
|
|
122
220
|
// where('field','value', operator?) or where([field, value])
|
|
123
221
|
where(fieldOrPair, value, operator) {
|
|
@@ -139,32 +237,38 @@ class SchemaQuery {
|
|
|
139
237
|
buildOptions() {
|
|
140
238
|
return {
|
|
141
239
|
collectionName: this.def.collectionName,
|
|
142
|
-
filters: this.filters
|
|
143
|
-
limit:
|
|
144
|
-
offset:
|
|
240
|
+
filters: this.filters,
|
|
241
|
+
limit: this._limit,
|
|
242
|
+
offset: this._offset,
|
|
145
243
|
sortBy: null,
|
|
146
|
-
fields: this.
|
|
244
|
+
fields: this.cachedFieldNames,
|
|
147
245
|
rawWhere: this.rawWhere,
|
|
148
246
|
};
|
|
149
247
|
}
|
|
248
|
+
getAdapter() {
|
|
249
|
+
if (this.cachedAdapter)
|
|
250
|
+
return this.cachedAdapter;
|
|
251
|
+
const adapter = this.manager.getAdapter(this.def.connectionName);
|
|
252
|
+
if (!adapter)
|
|
253
|
+
throw new AdapterMissingError(this.def.connectionName);
|
|
254
|
+
this.cachedAdapter = adapter;
|
|
255
|
+
return adapter;
|
|
256
|
+
}
|
|
150
257
|
to(update) {
|
|
151
258
|
this.pendingUpdate = update;
|
|
152
259
|
return this;
|
|
153
260
|
}
|
|
154
261
|
async get() {
|
|
155
|
-
const adapter = this.
|
|
156
|
-
if (!adapter)
|
|
157
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
262
|
+
const adapter = this.getAdapter();
|
|
158
263
|
const options = this.buildOptions();
|
|
159
264
|
const docs = adapter.get ? await adapter.get(options) : await adapter.getDocuments(options);
|
|
160
265
|
return docs;
|
|
161
266
|
}
|
|
162
267
|
async getOne() {
|
|
163
268
|
var _a;
|
|
164
|
-
const adapter = this.
|
|
165
|
-
if (!adapter)
|
|
166
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
269
|
+
const adapter = this.getAdapter();
|
|
167
270
|
const options = this.buildOptions();
|
|
271
|
+
options.limit = 1;
|
|
168
272
|
if (adapter.getOne) {
|
|
169
273
|
const one = await adapter.getOne(options);
|
|
170
274
|
return (_a = one) !== null && _a !== void 0 ? _a : null;
|
|
@@ -173,67 +277,78 @@ class SchemaQuery {
|
|
|
173
277
|
return results[0] || null;
|
|
174
278
|
}
|
|
175
279
|
async add(data) {
|
|
176
|
-
const adapter = this.
|
|
177
|
-
if
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const allowed = new Set(this.def.fields.map(f => f.name));
|
|
280
|
+
const adapter = this.getAdapter();
|
|
281
|
+
// 1. Filter restricted fields if configured
|
|
282
|
+
if (this.def.insertableFields) {
|
|
283
|
+
const allowed = new Set(this.def.insertableFields);
|
|
181
284
|
data = Object.fromEntries(Object.entries(data).filter(([k]) => allowed.has(k)));
|
|
182
285
|
}
|
|
286
|
+
else if (!this.def.allowUndefinedFields) {
|
|
287
|
+
// Exclude system fields or unspecified fields
|
|
288
|
+
data = Object.fromEntries(Object.entries(data).filter(([k]) => this.allowedFields.has(k)));
|
|
289
|
+
}
|
|
290
|
+
// 2. Apply defaults
|
|
291
|
+
for (const field of this.def.fields) {
|
|
292
|
+
if (data[field.name] === undefined && field.defaultValue !== undefined) {
|
|
293
|
+
if (field.defaultValue === 'NOW()') {
|
|
294
|
+
data[field.name] = new Date(); // Or string format depending on adapter
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
data[field.name] = field.defaultValue;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
183
301
|
return adapter.addDocument(this.def.collectionName, data);
|
|
184
302
|
}
|
|
185
303
|
async delete() {
|
|
186
|
-
const adapter = this.
|
|
187
|
-
|
|
188
|
-
|
|
304
|
+
const adapter = this.getAdapter();
|
|
305
|
+
// Mass delete check
|
|
306
|
+
if (!this.def.massDeleteAllowed && this.filters.length === 0 && !this._limit) {
|
|
307
|
+
// Enforce limit 1 if no filters and mass delete not allowed?
|
|
308
|
+
// User said: "if false, automatically add limit of 1"
|
|
309
|
+
this._limit = 1;
|
|
310
|
+
}
|
|
311
|
+
if (this.def.deleteType === 'softDelete') {
|
|
312
|
+
// Perform update instead
|
|
313
|
+
return this.to({ deletedOn: new Date() }).update();
|
|
314
|
+
}
|
|
189
315
|
const docs = await this.get();
|
|
190
|
-
// Expect each doc has an 'id' field
|
|
191
316
|
for (const d of docs) {
|
|
192
317
|
const id = d.id;
|
|
193
318
|
if (!id)
|
|
194
|
-
throw new
|
|
319
|
+
throw new DocumentMissingIdError('delete');
|
|
195
320
|
await adapter.deleteDocument(this.def.collectionName, id);
|
|
196
321
|
}
|
|
197
322
|
}
|
|
198
323
|
async deleteOne() {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return;
|
|
202
|
-
const adapter = this.manager.getAdapter(this.def.connectionName);
|
|
203
|
-
if (!adapter)
|
|
204
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
205
|
-
const id = one.id;
|
|
206
|
-
if (!id)
|
|
207
|
-
throw new Error('Document missing id; cannot deleteOne');
|
|
208
|
-
await adapter.deleteDocument(this.def.collectionName, id);
|
|
324
|
+
this._limit = 1;
|
|
325
|
+
return this.delete();
|
|
209
326
|
}
|
|
210
327
|
async update() {
|
|
211
|
-
const adapter = this.
|
|
212
|
-
if (!adapter)
|
|
213
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
328
|
+
const adapter = this.getAdapter();
|
|
214
329
|
if (!this.pendingUpdate)
|
|
215
|
-
throw new
|
|
330
|
+
throw new UpdatePayloadMissingError();
|
|
331
|
+
let data = this.pendingUpdate;
|
|
332
|
+
// Filter updatable fields
|
|
333
|
+
if (this.def.updatableFields) {
|
|
334
|
+
const allowed = new Set(this.def.updatableFields);
|
|
335
|
+
data = Object.fromEntries(Object.entries(data).filter(([k]) => allowed.has(k)));
|
|
336
|
+
}
|
|
337
|
+
// Mass edit check
|
|
338
|
+
if (!this.def.massEditAllowed && this.filters.length === 0 && !this._limit) {
|
|
339
|
+
this._limit = 1;
|
|
340
|
+
}
|
|
216
341
|
const docs = await this.get();
|
|
217
342
|
for (const d of docs) {
|
|
218
343
|
const id = d.id;
|
|
219
344
|
if (!id)
|
|
220
|
-
throw new
|
|
221
|
-
await adapter.updateDocument(this.def.collectionName, id,
|
|
345
|
+
throw new DocumentMissingIdError('update');
|
|
346
|
+
await adapter.updateDocument(this.def.collectionName, id, data);
|
|
222
347
|
}
|
|
223
348
|
}
|
|
224
349
|
async updateOne() {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
228
|
-
if (!this.pendingUpdate)
|
|
229
|
-
throw new Error('No update payload set; call to({ ... }) first');
|
|
230
|
-
const one = await this.getOne();
|
|
231
|
-
if (!one)
|
|
232
|
-
return;
|
|
233
|
-
const id = one.id;
|
|
234
|
-
if (!id)
|
|
235
|
-
throw new Error('Document missing id; cannot updateOne');
|
|
236
|
-
await adapter.updateDocument(this.def.collectionName, id, this.pendingUpdate);
|
|
350
|
+
this._limit = 1;
|
|
351
|
+
return this.update();
|
|
237
352
|
}
|
|
238
353
|
}
|
|
239
354
|
export class SchemaManager {
|
|
@@ -243,7 +358,7 @@ export class SchemaManager {
|
|
|
243
358
|
}
|
|
244
359
|
create(name) {
|
|
245
360
|
if (this.schemas.has(name)) {
|
|
246
|
-
throw new
|
|
361
|
+
throw new SchemaExistingError(name);
|
|
247
362
|
}
|
|
248
363
|
return new SchemaBuilder(this, name);
|
|
249
364
|
}
|
|
@@ -254,7 +369,7 @@ export class SchemaManager {
|
|
|
254
369
|
use(name) {
|
|
255
370
|
const def = this.schemas.get(name);
|
|
256
371
|
if (!def)
|
|
257
|
-
throw new
|
|
372
|
+
throw new SchemaMissingError(name);
|
|
258
373
|
return new SchemaQuery(this, def);
|
|
259
374
|
}
|
|
260
375
|
getAdapter(connectionName) {
|
|
@@ -275,13 +390,17 @@ export const schemas = (() => {
|
|
|
275
390
|
const conns = new Connections();
|
|
276
391
|
return new SchemaManager(conns);
|
|
277
392
|
})();
|
|
278
|
-
export { createOrm } from './orm';
|
|
279
|
-
export { parseConnectionsDsl, toNormalizedConnections } from './env';
|
|
280
|
-
export { documentationMd, markdownToHtml, getDocumentationHtml } from './docs';
|
|
281
|
-
// Export the simplified Mapper
|
|
282
|
-
export { Mapper, createMapper } from './mapper';
|
|
283
|
-
export { default } from './mapper';
|
|
393
|
+
export { createOrm } from './orm/index.js';
|
|
394
|
+
export { parseConnectionsDsl, toNormalizedConnections } from './env.js';
|
|
395
|
+
export { documentationMd, markdownToHtml, getDocumentationHtml } from './docs.js';
|
|
396
|
+
// Export the simplified Mapper and default instance
|
|
397
|
+
export { Mapper, createMapper } from './mapper.js';
|
|
398
|
+
export { default } from './mapper.js';
|
|
284
399
|
// Export the new fluent/static API
|
|
285
|
-
export { StaticMapper } from './fluent-mapper';
|
|
400
|
+
export { StaticMapper } from './fluent-mapper.js';
|
|
286
401
|
// Export the new config-based system
|
|
287
|
-
export { ConfigBasedMapper, ConfigLoader, createConfigMapper, getConfigMapper, createDefaultMapper } from './config';
|
|
402
|
+
export { ConfigBasedMapper, ConfigLoader, createConfigMapper, getConfigMapper, createDefaultMapper } from './config.js';
|
|
403
|
+
// Export database adapters
|
|
404
|
+
export { MySQLAdapter, createMySQLAdapter, PostgreSQLAdapter, createPostgreSQLAdapter, MongoDBAdapter, createMongoDBAdapter, APIAdapter, createAPIAdapter, createAdapter, createAdapterFromUrl, autoAttachAdapter } from './adapters/index.js';
|
|
405
|
+
export { MapperError, AdapterMissingError, UpdatePayloadMissingError, DocumentMissingIdError, ConnectionExistingError, ConnectionUnknownError, SchemaExistingError, SchemaMissingError, SchemaConfigurationError, } from './errors.js';
|
|
406
|
+
export { Connector, mapper } from './connector.js';
|
package/dist/mapper.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Connections, SchemaManager } from './index';
|
|
1
|
+
import { Connections, SchemaManager } from './index.js';
|
|
2
2
|
export declare class Mapper {
|
|
3
3
|
private connections;
|
|
4
4
|
private schemaManager;
|
|
5
5
|
private static instance;
|
|
6
|
+
private configured;
|
|
6
7
|
constructor();
|
|
7
8
|
static getInstance(): Mapper;
|
|
8
9
|
autoConfigure(): this;
|
package/dist/mapper.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Connections, SchemaManager } from './index';
|
|
1
|
+
import { Connections, SchemaManager } from './index.js';
|
|
2
2
|
export class Mapper {
|
|
3
3
|
constructor() {
|
|
4
|
+
this.configured = false;
|
|
4
5
|
this.connections = new Connections();
|
|
5
6
|
this.schemaManager = new SchemaManager(this.connections);
|
|
6
7
|
}
|
|
@@ -12,6 +13,9 @@ export class Mapper {
|
|
|
12
13
|
}
|
|
13
14
|
// Auto-configuration based on environment or defaults
|
|
14
15
|
autoConfigure() {
|
|
16
|
+
if (this.configured)
|
|
17
|
+
return this;
|
|
18
|
+
this.configured = true;
|
|
15
19
|
// Check for environment variables or config files
|
|
16
20
|
const envConfig = this.detectEnvironmentConfig();
|
|
17
21
|
if (envConfig) {
|
package/dist/orm/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { DbAdapter, QueryOptions } from './types';
|
|
1
|
+
import type { DbAdapter, QueryOptions } from './types.js';
|
|
2
2
|
export declare function createOrm(adapter: DbAdapter): {
|
|
3
|
-
get(options: QueryOptions): Promise<import("./types").DocumentData[]>;
|
|
3
|
+
get(options: QueryOptions): Promise<import("./types.js").DocumentData[]>;
|
|
4
4
|
getOne(options: QueryOptions): Promise<any>;
|
|
5
|
-
getDocuments(options: QueryOptions): Promise<import("./types").DocumentData[]>;
|
|
5
|
+
getDocuments(options: QueryOptions): Promise<import("./types.js").DocumentData[]>;
|
|
6
6
|
addDocument(collectionName: string, data: Record<string, any>): Promise<string>;
|
|
7
7
|
updateDocument(collectionName: string, docId: string, data: Record<string, any>): Promise<void>;
|
|
8
8
|
deleteDocument(collectionName: string, docId: string): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Mapper } from './fluent-mapper.js';
|
|
2
|
+
async function main() {
|
|
3
|
+
// 1. Connection setup (mock)
|
|
4
|
+
Mapper.makeConnection('custom', 'api', { url: 'http://localhost' });
|
|
5
|
+
// 2. Schema Definition using the new API
|
|
6
|
+
const userSchema = Mapper.schemas('users');
|
|
7
|
+
userSchema.fields = {
|
|
8
|
+
'id': ['integer', 'auto-increment'],
|
|
9
|
+
'name': ['string', 'max.20', 'unique'],
|
|
10
|
+
'gender': ['string', 'enum', ['male', 'female', 'other']],
|
|
11
|
+
'createdOn': ['datetime', 'default_current_datetime'],
|
|
12
|
+
'role': ['string', 'default.value', 'user']
|
|
13
|
+
};
|
|
14
|
+
userSchema.insertableFields = ['name', 'gender', 'role']; // exclude id, createdOn
|
|
15
|
+
userSchema.updatableFields = ['name', 'gender'];
|
|
16
|
+
userSchema.deleteType = 'softDelete';
|
|
17
|
+
userSchema.massDeleteAllowed = false;
|
|
18
|
+
console.log("Schema defined.");
|
|
19
|
+
// 3. User Query Scenarios
|
|
20
|
+
// Scenario A: Mapper.connection('name').table('name')
|
|
21
|
+
// We don't have a real DB so this will fail at execution but we check the builder construction.
|
|
22
|
+
const query1 = Mapper.connection('default').table('users');
|
|
23
|
+
console.log("Query 1 built:", query1);
|
|
24
|
+
// Scenario B: Mapper.connection('name').schemas('name').get('users').limit(1)
|
|
25
|
+
// 'users' in get() might be field selection if schema is 'name'.
|
|
26
|
+
// Let's assume 'users' is the schema name.
|
|
27
|
+
// Code: Mapper.connection('default').schemas('users').get('id', 'name').limit(1)
|
|
28
|
+
const query2 = Mapper.connection('default').schemas('users').get('id', 'name').limit(1);
|
|
29
|
+
console.log("Query 2 built (select fields):", query2);
|
|
30
|
+
// Scenario C: Mapper.schemas('name').get('field1','field2').limit(2).offset(20)
|
|
31
|
+
const query3 = Mapper.schemas('users').get('name', 'gender').limit(2).offset(20);
|
|
32
|
+
console.log("Query 3 built:", query3);
|
|
33
|
+
// 4. Test logic (mock execution would happen here)
|
|
34
|
+
// Since we don't have a real adapter that works without network/db, we just stop here.
|
|
35
|
+
// If we had an in-memory adapter we could test output.
|
|
36
|
+
}
|
|
37
|
+
main().catch(console.error);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Mapper } from './fluent-mapper.js';
|
|
2
|
+
async function main() {
|
|
3
|
+
// 1. Connection setup (mock) with new API
|
|
4
|
+
// Using configuration object directly
|
|
5
|
+
// Mapper.connection(['type': 'type', 'username':'username' ]) -> { type: 'api', ... }
|
|
6
|
+
const conn = Mapper.connection({ type: 'api', url: 'http://example.com' });
|
|
7
|
+
console.log("Connection created:", conn);
|
|
8
|
+
// 2. Insert with new API
|
|
9
|
+
// Mapper.connection('connectionName').collection('name').insert({...})
|
|
10
|
+
// Let's use the temp connection we just made (it is anonymous/temp in our implementation if using config object,
|
|
11
|
+
// but wait, `connection({ type: ... })` returns a selector bound to a temp name.
|
|
12
|
+
// We need to access a collection/table from the connection selector.
|
|
13
|
+
// The user requirement: Mapper.connection(...).collection('name').insert(...)
|
|
14
|
+
// Check references: FluentConnectionSelector has `schema` and `query` and `table`.
|
|
15
|
+
// Does it have `collection`? No, let's check FluentConnectionSelector.
|
|
16
|
+
// It has `schema(name)` and `query(name)` and `table(name)`.
|
|
17
|
+
// We should add `collection(name)` alias.
|
|
18
|
+
}
|
|
19
|
+
main().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@neupgroup/mapper",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "Neup.Mapper core library for schema and mapping utilities",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"module": "dist/index.js",
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
|
-
"files": [
|
|
10
|
-
"dist"
|
|
11
|
-
],
|
|
12
|
-
"sideEffects": false,
|
|
13
|
-
"scripts": {
|
|
14
|
-
"build": "tsc -p ./tsconfig.json"
|
|
15
|
-
},
|
|
16
|
-
"publishConfig": {
|
|
17
|
-
"access": "public"
|
|
18
|
-
},
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"@types/node": "^24.10.1",
|
|
21
|
-
"typescript": "^5.9.3"
|
|
22
|
-
}
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@neupgroup/mapper",
|
|
3
|
+
"version": "1.2.4",
|
|
4
|
+
"description": "Neup.Mapper core library for schema and mapping utilities",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p ./tsconfig.json"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^24.10.1",
|
|
21
|
+
"typescript": "^5.9.3"
|
|
22
|
+
}
|
|
23
|
+
}
|