@neupgroup/mapper 1.2.3 → 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 -14
- package/dist/index.js +187 -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,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AdapterMissingError, ConnectionExistingError, ConnectionUnknownError, DocumentMissingIdError, SchemaExistingError, SchemaMissingError, UpdatePayloadMissingError, } from './errors.js';
|
|
2
2
|
class AdapterRegistry {
|
|
3
3
|
constructor() {
|
|
4
4
|
this.adaptersByConnection = new Map();
|
|
@@ -28,20 +28,20 @@ export class Connections {
|
|
|
28
28
|
}
|
|
29
29
|
create(name, type) {
|
|
30
30
|
if (this.connections.has(name)) {
|
|
31
|
-
throw new
|
|
31
|
+
throw new ConnectionExistingError(name);
|
|
32
32
|
}
|
|
33
33
|
return new ConnectionBuilder(this, name, type);
|
|
34
34
|
}
|
|
35
35
|
register(config) {
|
|
36
36
|
if (this.connections.has(config.name)) {
|
|
37
|
-
throw new
|
|
37
|
+
throw new ConnectionExistingError(config.name);
|
|
38
38
|
}
|
|
39
39
|
this.connections.set(config.name, config);
|
|
40
40
|
return this;
|
|
41
41
|
}
|
|
42
42
|
attachAdapter(name, adapter) {
|
|
43
43
|
if (!this.connections.has(name)) {
|
|
44
|
-
throw new
|
|
44
|
+
throw new ConnectionUnknownError('attach adapter', name);
|
|
45
45
|
}
|
|
46
46
|
this.adapters.attach(name, adapter);
|
|
47
47
|
return this;
|
|
@@ -56,22 +56,69 @@ export class Connections {
|
|
|
56
56
|
return Array.from(this.connections.values());
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
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) {
|
|
60
92
|
let allowUndefinedFields = false;
|
|
61
93
|
const fields = [];
|
|
62
94
|
for (const [key, descriptor] of Object.entries(struct)) {
|
|
63
95
|
if (key === '?field') {
|
|
64
|
-
// Presence of '?field' enables accepting fields not defined in the schema
|
|
65
96
|
allowUndefinedFields = true;
|
|
66
97
|
continue;
|
|
67
98
|
}
|
|
68
|
-
const tokens = descriptor.split(/\s+/).map(t => t.trim().toLowerCase()).filter(Boolean);
|
|
69
99
|
const field = {
|
|
70
100
|
name: key,
|
|
71
|
-
type:
|
|
72
|
-
|
|
73
|
-
autoIncrement: tokens.includes('auto_increment') || tokens.includes('autoincrement'),
|
|
101
|
+
type: 'string', // default
|
|
102
|
+
config: Array.isArray(descriptor) ? descriptor : [descriptor]
|
|
74
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
|
+
}
|
|
75
122
|
fields.push(field);
|
|
76
123
|
}
|
|
77
124
|
return { fields, allowUndefinedFields };
|
|
@@ -82,12 +129,29 @@ class SchemaBuilder {
|
|
|
82
129
|
this.name = name;
|
|
83
130
|
this.fields = [];
|
|
84
131
|
this.allowUndefinedFields = false;
|
|
132
|
+
this.deleteType = 'hardDelete';
|
|
133
|
+
this.massDeleteAllowed = true;
|
|
134
|
+
this.massEditAllowed = true;
|
|
85
135
|
}
|
|
86
136
|
use(options) {
|
|
87
137
|
this.connectionName = options.connection;
|
|
88
138
|
this.collectionName = options.collection;
|
|
89
139
|
return this;
|
|
90
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
|
+
}
|
|
91
155
|
setStructure(structure) {
|
|
92
156
|
if (Array.isArray(structure)) {
|
|
93
157
|
this.fields = structure;
|
|
@@ -100,14 +164,25 @@ class SchemaBuilder {
|
|
|
100
164
|
}
|
|
101
165
|
// Finalize schema registration
|
|
102
166
|
if (!this.connectionName || !this.collectionName) {
|
|
103
|
-
|
|
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.
|
|
104
171
|
}
|
|
172
|
+
const fieldsMap = new Map();
|
|
173
|
+
this.fields.forEach(f => fieldsMap.set(f.name, f));
|
|
105
174
|
this.manager.register({
|
|
106
175
|
name: this.name,
|
|
107
|
-
connectionName: this.connectionName,
|
|
176
|
+
connectionName: this.connectionName, // Assuming set
|
|
108
177
|
collectionName: this.collectionName,
|
|
109
178
|
fields: this.fields,
|
|
179
|
+
fieldsMap,
|
|
110
180
|
allowUndefinedFields: this.allowUndefinedFields,
|
|
181
|
+
insertableFields: this.insertableFields,
|
|
182
|
+
updatableFields: this.updatableFields,
|
|
183
|
+
deleteType: this.deleteType,
|
|
184
|
+
massDeleteAllowed: this.massDeleteAllowed,
|
|
185
|
+
massEditAllowed: this.massEditAllowed
|
|
111
186
|
});
|
|
112
187
|
return this.manager;
|
|
113
188
|
}
|
|
@@ -119,6 +194,28 @@ class SchemaQuery {
|
|
|
119
194
|
this.filters = [];
|
|
120
195
|
this.rawWhere = null;
|
|
121
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;
|
|
122
219
|
}
|
|
123
220
|
// where('field','value', operator?) or where([field, value])
|
|
124
221
|
where(fieldOrPair, value, operator) {
|
|
@@ -140,32 +237,38 @@ class SchemaQuery {
|
|
|
140
237
|
buildOptions() {
|
|
141
238
|
return {
|
|
142
239
|
collectionName: this.def.collectionName,
|
|
143
|
-
filters: this.filters
|
|
144
|
-
limit:
|
|
145
|
-
offset:
|
|
240
|
+
filters: this.filters,
|
|
241
|
+
limit: this._limit,
|
|
242
|
+
offset: this._offset,
|
|
146
243
|
sortBy: null,
|
|
147
|
-
fields: this.
|
|
244
|
+
fields: this.cachedFieldNames,
|
|
148
245
|
rawWhere: this.rawWhere,
|
|
149
246
|
};
|
|
150
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
|
+
}
|
|
151
257
|
to(update) {
|
|
152
258
|
this.pendingUpdate = update;
|
|
153
259
|
return this;
|
|
154
260
|
}
|
|
155
261
|
async get() {
|
|
156
|
-
const adapter = this.
|
|
157
|
-
if (!adapter)
|
|
158
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
262
|
+
const adapter = this.getAdapter();
|
|
159
263
|
const options = this.buildOptions();
|
|
160
264
|
const docs = adapter.get ? await adapter.get(options) : await adapter.getDocuments(options);
|
|
161
265
|
return docs;
|
|
162
266
|
}
|
|
163
267
|
async getOne() {
|
|
164
268
|
var _a;
|
|
165
|
-
const adapter = this.
|
|
166
|
-
if (!adapter)
|
|
167
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
269
|
+
const adapter = this.getAdapter();
|
|
168
270
|
const options = this.buildOptions();
|
|
271
|
+
options.limit = 1;
|
|
169
272
|
if (adapter.getOne) {
|
|
170
273
|
const one = await adapter.getOne(options);
|
|
171
274
|
return (_a = one) !== null && _a !== void 0 ? _a : null;
|
|
@@ -174,67 +277,78 @@ class SchemaQuery {
|
|
|
174
277
|
return results[0] || null;
|
|
175
278
|
}
|
|
176
279
|
async add(data) {
|
|
177
|
-
const adapter = this.
|
|
178
|
-
if
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
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);
|
|
182
284
|
data = Object.fromEntries(Object.entries(data).filter(([k]) => allowed.has(k)));
|
|
183
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
|
+
}
|
|
184
301
|
return adapter.addDocument(this.def.collectionName, data);
|
|
185
302
|
}
|
|
186
303
|
async delete() {
|
|
187
|
-
const adapter = this.
|
|
188
|
-
|
|
189
|
-
|
|
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
|
+
}
|
|
190
315
|
const docs = await this.get();
|
|
191
|
-
// Expect each doc has an 'id' field
|
|
192
316
|
for (const d of docs) {
|
|
193
317
|
const id = d.id;
|
|
194
318
|
if (!id)
|
|
195
|
-
throw new
|
|
319
|
+
throw new DocumentMissingIdError('delete');
|
|
196
320
|
await adapter.deleteDocument(this.def.collectionName, id);
|
|
197
321
|
}
|
|
198
322
|
}
|
|
199
323
|
async deleteOne() {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return;
|
|
203
|
-
const adapter = this.manager.getAdapter(this.def.connectionName);
|
|
204
|
-
if (!adapter)
|
|
205
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
206
|
-
const id = one.id;
|
|
207
|
-
if (!id)
|
|
208
|
-
throw new Error('Document missing id; cannot deleteOne');
|
|
209
|
-
await adapter.deleteDocument(this.def.collectionName, id);
|
|
324
|
+
this._limit = 1;
|
|
325
|
+
return this.delete();
|
|
210
326
|
}
|
|
211
327
|
async update() {
|
|
212
|
-
const adapter = this.
|
|
213
|
-
if (!adapter)
|
|
214
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
328
|
+
const adapter = this.getAdapter();
|
|
215
329
|
if (!this.pendingUpdate)
|
|
216
|
-
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
|
+
}
|
|
217
341
|
const docs = await this.get();
|
|
218
342
|
for (const d of docs) {
|
|
219
343
|
const id = d.id;
|
|
220
344
|
if (!id)
|
|
221
|
-
throw new
|
|
222
|
-
await adapter.updateDocument(this.def.collectionName, id,
|
|
345
|
+
throw new DocumentMissingIdError('update');
|
|
346
|
+
await adapter.updateDocument(this.def.collectionName, id, data);
|
|
223
347
|
}
|
|
224
348
|
}
|
|
225
349
|
async updateOne() {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
throw new Error(`No adapter attached for connection '${this.def.connectionName}'`);
|
|
229
|
-
if (!this.pendingUpdate)
|
|
230
|
-
throw new Error('No update payload set; call to({ ... }) first');
|
|
231
|
-
const one = await this.getOne();
|
|
232
|
-
if (!one)
|
|
233
|
-
return;
|
|
234
|
-
const id = one.id;
|
|
235
|
-
if (!id)
|
|
236
|
-
throw new Error('Document missing id; cannot updateOne');
|
|
237
|
-
await adapter.updateDocument(this.def.collectionName, id, this.pendingUpdate);
|
|
350
|
+
this._limit = 1;
|
|
351
|
+
return this.update();
|
|
238
352
|
}
|
|
239
353
|
}
|
|
240
354
|
export class SchemaManager {
|
|
@@ -244,7 +358,7 @@ export class SchemaManager {
|
|
|
244
358
|
}
|
|
245
359
|
create(name) {
|
|
246
360
|
if (this.schemas.has(name)) {
|
|
247
|
-
throw new
|
|
361
|
+
throw new SchemaExistingError(name);
|
|
248
362
|
}
|
|
249
363
|
return new SchemaBuilder(this, name);
|
|
250
364
|
}
|
|
@@ -255,7 +369,7 @@ export class SchemaManager {
|
|
|
255
369
|
use(name) {
|
|
256
370
|
const def = this.schemas.get(name);
|
|
257
371
|
if (!def)
|
|
258
|
-
throw new
|
|
372
|
+
throw new SchemaMissingError(name);
|
|
259
373
|
return new SchemaQuery(this, def);
|
|
260
374
|
}
|
|
261
375
|
getAdapter(connectionName) {
|
|
@@ -276,13 +390,17 @@ export const schemas = (() => {
|
|
|
276
390
|
const conns = new Connections();
|
|
277
391
|
return new SchemaManager(conns);
|
|
278
392
|
})();
|
|
279
|
-
export { createOrm } from './orm';
|
|
280
|
-
export { parseConnectionsDsl, toNormalizedConnections } from './env';
|
|
281
|
-
export { documentationMd, markdownToHtml, getDocumentationHtml } from './docs';
|
|
393
|
+
export { createOrm } from './orm/index.js';
|
|
394
|
+
export { parseConnectionsDsl, toNormalizedConnections } from './env.js';
|
|
395
|
+
export { documentationMd, markdownToHtml, getDocumentationHtml } from './docs.js';
|
|
282
396
|
// Export the simplified Mapper and default instance
|
|
283
|
-
export { Mapper, createMapper } from './mapper';
|
|
284
|
-
export default
|
|
397
|
+
export { Mapper, createMapper } from './mapper.js';
|
|
398
|
+
export { default } from './mapper.js';
|
|
285
399
|
// Export the new fluent/static API
|
|
286
|
-
export { StaticMapper } from './fluent-mapper';
|
|
400
|
+
export { StaticMapper } from './fluent-mapper.js';
|
|
287
401
|
// Export the new config-based system
|
|
288
|
-
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
|
+
}
|