@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/README.md
CHANGED
|
@@ -1,706 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Documentation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Welcome to the documentation for `@neupgroup/mapper`.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @neupgroup/mapper
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## 🚀 Quick Start Options
|
|
12
|
-
|
|
13
|
-
### **Option 1: One-Import Quick Start**
|
|
14
|
-
**The simplest way to get started - just import and use:**
|
|
15
|
-
|
|
16
|
-
```ts
|
|
17
|
-
import Mapper from '@neupgroup/mapper'
|
|
18
|
-
|
|
19
|
-
// 1. Define a schema (Mapper auto-configures with sensible defaults)
|
|
20
|
-
Mapper.schema('users')
|
|
21
|
-
.use({ connection: 'default', collection: 'users' })
|
|
22
|
-
.setStructure([
|
|
23
|
-
{ name: 'id', type: 'int', autoIncrement: true },
|
|
24
|
-
{ name: 'name', type: 'string' },
|
|
25
|
-
{ name: 'email', type: 'string' }
|
|
26
|
-
])
|
|
27
|
-
|
|
28
|
-
// 2. Use immediately - no setup required!
|
|
29
|
-
await Mapper.add('users', { name: 'Alice', email: 'alice@example.com' })
|
|
30
|
-
const users = await Mapper.get('users')
|
|
31
|
-
const user = await Mapper.getOne('users', { email: 'alice@example.com' })
|
|
32
|
-
await Mapper.update('users', { email: 'alice@example.com' }, { name: 'Alice Cooper' })
|
|
33
|
-
await Mapper.delete('users', { email: 'alice@example.com' })
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### **Option 2: Configuration-Based Approach**
|
|
37
|
-
**Use configuration files to manage connections and schemas:**
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
import { createConfigMapper } from '@neupgroup/mapper'
|
|
41
|
-
|
|
42
|
-
// Define your configuration
|
|
43
|
-
const config = {
|
|
44
|
-
connections: [
|
|
45
|
-
['mydb', 'sql', 'user', 'myapp', 'localhost', 5432],
|
|
46
|
-
['myapi', 'api', 'https://api.example.com']
|
|
47
|
-
],
|
|
48
|
-
schemas: {
|
|
49
|
-
users: {
|
|
50
|
-
connection: 'mydb',
|
|
51
|
-
collection: 'users',
|
|
52
|
-
structure: [
|
|
53
|
-
{ name: 'id', type: 'int', autoIncrement: true },
|
|
54
|
-
{ name: 'name', type: 'string' },
|
|
55
|
-
{ name: 'email', type: 'string' }
|
|
56
|
-
]
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Create mapper from config
|
|
62
|
-
const mapper = createConfigMapper(config)
|
|
63
|
-
|
|
64
|
-
// Use the mapper
|
|
65
|
-
await mapper.useConnection('mydb').table('users').add({ name: 'Alice', email: 'alice@example.com' })
|
|
66
|
-
const users = await mapper.useConnection('mydb').table('users').select().execute()
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### **Option 3: PHP-Style Fluent API**
|
|
70
|
-
**Use static method chaining for dynamic connections:**
|
|
71
|
-
|
|
72
|
-
```ts
|
|
73
|
-
import { StaticMapper as Mapper } from '@neupgroup/mapper'
|
|
74
|
-
|
|
75
|
-
// Create persistent connections
|
|
76
|
-
Mapper.makeConnection('mydb', 'mysql', {
|
|
77
|
-
host: 'localhost',
|
|
78
|
-
user: 'root',
|
|
79
|
-
password: 'password',
|
|
80
|
-
database: 'myapp'
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
// Use connections with method chaining
|
|
84
|
-
const users = await Mapper.useConnection('mydb')
|
|
85
|
-
.table('users')
|
|
86
|
-
.select()
|
|
87
|
-
.where('active', true)
|
|
88
|
-
.execute()
|
|
89
|
-
|
|
90
|
-
// Create temporary connections on-the-fly
|
|
91
|
-
const tempData = await Mapper.makeTempConnection('mongodb', {
|
|
92
|
-
url: 'mongodb://localhost:27017',
|
|
93
|
-
database: 'temp'
|
|
94
|
-
})
|
|
95
|
-
.collection('cache')
|
|
96
|
-
.find({ expired: false })
|
|
97
|
-
.execute()
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### **Auto-Configuration Magic** ✨
|
|
101
|
-
|
|
102
|
-
The Mapper automatically configures itself based on your environment:
|
|
103
|
-
|
|
104
|
-
- **Environment Variables**: `DATABASE_URL=mysql://user:pass@host:port/db`
|
|
105
|
-
- **Browser Global**: `window.__MAPPER_CONFIG__`
|
|
106
|
-
- **Default Fallback**: In-memory API connection for instant prototyping
|
|
107
|
-
|
|
108
|
-
**Connection type auto-detection:**
|
|
109
|
-
```
|
|
110
|
-
mysql://... → MySQL
|
|
111
|
-
postgres://... → PostgreSQL
|
|
112
|
-
mongodb://... → MongoDB
|
|
113
|
-
firestore://... → Firestore
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### **Manual Configuration (Optional)**
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
// Connect to your database
|
|
120
|
-
Mapper.connect('mydb', 'mysql', {
|
|
121
|
-
host: 'localhost',
|
|
122
|
-
port: 3306,
|
|
123
|
-
user: 'root',
|
|
124
|
-
password: 'password',
|
|
125
|
-
database: 'myapp'
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
// Or use environment variables
|
|
129
|
-
// DATABASE_URL=mysql://root:password@localhost:3306/myapp
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## 🛠️ Complete Usage Examples
|
|
133
|
-
|
|
134
|
-
### **Example 1: Zero-Configuration Setup**
|
|
135
|
-
```ts
|
|
136
|
-
import Mapper from '@neupgroup/mapper'
|
|
137
|
-
|
|
138
|
-
// Works immediately with in-memory storage
|
|
139
|
-
const users = await Mapper.get('users') // Returns empty array
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### **Example 2: Environment-Based Configuration**
|
|
143
|
-
```bash
|
|
144
|
-
# Set environment variable
|
|
145
|
-
export DATABASE_URL=mysql://user:password@localhost:3306/myapp
|
|
146
|
-
|
|
147
|
-
# Or in browser
|
|
148
|
-
window.__MAPPER_CONFIG__ = {
|
|
149
|
-
connection: {
|
|
150
|
-
name: 'mydb',
|
|
151
|
-
type: 'mysql',
|
|
152
|
-
key: { host: 'localhost', user: 'root', password: 'pass', database: 'myapp' }
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
import Mapper from '@neupgroup/mapper'
|
|
159
|
-
|
|
160
|
-
// Automatically configured from environment
|
|
161
|
-
const users = await Mapper.get('users')
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### **Example 3: Schema with Multiple Field Types**
|
|
165
|
-
```ts
|
|
166
|
-
import Mapper from '@neupgroup/mapper'
|
|
167
|
-
|
|
168
|
-
Mapper.schema('products')
|
|
169
|
-
.use({ connection: 'default', collection: 'products' })
|
|
170
|
-
.setStructure([
|
|
171
|
-
{ name: 'id', type: 'int', autoIncrement: true },
|
|
172
|
-
{ name: 'name', type: 'string' },
|
|
173
|
-
{ name: 'price', type: 'number' },
|
|
174
|
-
{ name: 'inStock', type: 'boolean' },
|
|
175
|
-
{ name: 'createdAt', type: 'date' },
|
|
176
|
-
{ name: 'categoryId', type: 'int' }
|
|
177
|
-
])
|
|
178
|
-
|
|
179
|
-
// Add product
|
|
180
|
-
await Mapper.add('products', {
|
|
181
|
-
name: 'Laptop',
|
|
182
|
-
price: 999.99,
|
|
183
|
-
inStock: true,
|
|
184
|
-
createdAt: new Date(),
|
|
185
|
-
categoryId: 1
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
// Get products with filters
|
|
189
|
-
const expensiveProducts = await Mapper.get('products', { price: 500 }, '>')
|
|
190
|
-
const inStockProducts = await Mapper.get('products', { inStock: true })
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### **Example 4: Advanced Query Operations**
|
|
194
|
-
```ts
|
|
195
|
-
import Mapper from '@neupgroup/mapper'
|
|
196
|
-
|
|
197
|
-
// Complex queries using the underlying API
|
|
198
|
-
const query = Mapper.use('users')
|
|
199
|
-
.where('age', 18, '>=')
|
|
200
|
-
.where('status', 'active')
|
|
201
|
-
|
|
202
|
-
const activeAdults = await query.get()
|
|
203
|
-
const firstActiveAdult = await query.getOne()
|
|
204
|
-
|
|
205
|
-
// Update multiple records
|
|
206
|
-
await query.to({ lastLogin: new Date() }).update()
|
|
207
|
-
|
|
208
|
-
// Delete with complex conditions
|
|
209
|
-
await Mapper.use('users')
|
|
210
|
-
.where('lastLogin', new Date('2023-01-01'), '<')
|
|
211
|
-
.delete()
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### **Example 5: Multiple Databases**
|
|
215
|
-
```ts
|
|
216
|
-
import Mapper from '@neupgroup/mapper'
|
|
217
|
-
|
|
218
|
-
// Connect to multiple databases
|
|
219
|
-
Mapper.connect('mysql_db', 'mysql', {
|
|
220
|
-
host: 'localhost',
|
|
221
|
-
user: 'root',
|
|
222
|
-
password: 'password',
|
|
223
|
-
database: 'main_app'
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
Mapper.connect('mongo_cache', 'mongodb', {
|
|
227
|
-
uri: 'mongodb://localhost:27017',
|
|
228
|
-
database: 'cache'
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
// Use different connections for different schemas
|
|
232
|
-
Mapper.schema('users')
|
|
233
|
-
.use({ connection: 'mysql_db', collection: 'users' })
|
|
234
|
-
.setStructure([...])
|
|
235
|
-
|
|
236
|
-
Mapper.schema('sessions')
|
|
237
|
-
.use({ connection: 'mongo_cache', collection: 'sessions' })
|
|
238
|
-
.setStructure([...])
|
|
239
|
-
|
|
240
|
-
// Query from different databases
|
|
241
|
-
const users = await Mapper.get('users') // From MySQL
|
|
242
|
-
const sessions = await Mapper.get('sessions') // From MongoDB
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## 🌍 Environment Configuration Guide
|
|
246
|
-
|
|
247
|
-
### **Node.js Environment Variables**
|
|
248
|
-
|
|
249
|
-
The Mapper automatically detects these environment variables:
|
|
250
|
-
|
|
251
|
-
```bash
|
|
252
|
-
# Basic database URL (auto-detects type)
|
|
253
|
-
DATABASE_URL=mysql://user:password@localhost:3306/myapp
|
|
254
|
-
|
|
255
|
-
# Or specific connection types
|
|
256
|
-
MYSQL_URL=mysql://user:password@localhost:3306/myapp
|
|
257
|
-
POSTGRES_URL=postgres://user:password@localhost:5432/myapp
|
|
258
|
-
MONGODB_URL=mongodb://localhost:27017/myapp
|
|
259
|
-
FIRESTORE_URL=firestore://project-id
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### **Browser Environment**
|
|
263
|
-
|
|
264
|
-
For client-side applications, use the global configuration:
|
|
265
|
-
|
|
266
|
-
```html
|
|
267
|
-
<script>
|
|
268
|
-
window.__MAPPER_CONFIG__ = {
|
|
269
|
-
connection: {
|
|
270
|
-
name: 'api',
|
|
271
|
-
type: 'api',
|
|
272
|
-
key: {
|
|
273
|
-
endpoint: 'https://api.example.com',
|
|
274
|
-
apiKey: 'your-api-key'
|
|
275
|
-
}
|
|
276
|
-
},
|
|
277
|
-
schemas: [
|
|
278
|
-
{
|
|
279
|
-
name: 'users',
|
|
280
|
-
connection: 'api',
|
|
281
|
-
collection: 'users',
|
|
282
|
-
structure: [
|
|
283
|
-
{ name: 'id', type: 'int' },
|
|
284
|
-
{ name: 'name', type: 'string' }
|
|
285
|
-
]
|
|
286
|
-
}
|
|
287
|
-
]
|
|
288
|
-
}
|
|
289
|
-
</script>
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### **Configuration Priority Order**
|
|
293
|
-
|
|
294
|
-
1. **Manual Configuration**: `Mapper.connect()` calls
|
|
295
|
-
2. **Environment Variables**: `DATABASE_URL` and others
|
|
296
|
-
3. **Browser Global**: `window.__MAPPER_CONFIG__`
|
|
297
|
-
4. **Default Fallback**: In-memory API connection
|
|
298
|
-
|
|
299
|
-
### **Docker & Production Setup**
|
|
300
|
-
|
|
301
|
-
```dockerfile
|
|
302
|
-
# Dockerfile
|
|
303
|
-
ENV DATABASE_URL=mysql://user:password@db:3306/myapp
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
```yaml
|
|
307
|
-
# docker-compose.yml
|
|
308
|
-
services:
|
|
309
|
-
app:
|
|
310
|
-
environment:
|
|
311
|
-
- DATABASE_URL=mysql://user:password@db:3306/myapp
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### **Configuration Validation**
|
|
315
|
-
|
|
316
|
-
```ts
|
|
317
|
-
import Mapper from '@neupgroup/mapper'
|
|
318
|
-
|
|
319
|
-
// Check current configuration
|
|
320
|
-
console.log('Connections:', Mapper.getConnections().list())
|
|
321
|
-
console.log('Schemas:', Mapper.getSchemaManager().list())
|
|
322
|
-
|
|
323
|
-
// Verify auto-configuration worked
|
|
324
|
-
const config = Mapper.getConnections().get('default')
|
|
325
|
-
if (!config) {
|
|
326
|
-
console.log('No auto-configuration detected, using manual setup...')
|
|
327
|
-
Mapper.connect('manual', 'mysql', { /* config */ })
|
|
328
|
-
}
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## Advanced Usage (Original API)
|
|
332
|
-
|
|
333
|
-
For more control, you can still use the original granular API:
|
|
334
|
-
|
|
335
|
-
```ts
|
|
336
|
-
import { connection, schema } from '@neupgroup/mapper'
|
|
337
|
-
import type { DbAdapter, QueryOptions } from '@neupgroup/mapper'
|
|
338
|
-
|
|
339
|
-
// 1) Define connections
|
|
340
|
-
const conRegistry = connection()
|
|
341
|
-
conRegistry.create('mysql_prod', 'mysql').key({
|
|
342
|
-
host: '127.0.0.1',
|
|
343
|
-
port: 3306,
|
|
344
|
-
user: 'root',
|
|
345
|
-
password: 's3cr3t',
|
|
346
|
-
database: 'appdb',
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
// 2) Attach an adapter for the connection
|
|
350
|
-
const adapter: DbAdapter = {
|
|
351
|
-
async getDocuments(options: QueryOptions) { return [] },
|
|
352
|
-
async addDocument(collectionName: string, data: Record<string, any>) { return 'new-id' },
|
|
353
|
-
async updateDocument(collectionName: string, docId: string, data: Record<string, any>) { },
|
|
354
|
-
async deleteDocument(collectionName: string, docId: string) { },
|
|
355
|
-
}
|
|
356
|
-
conRegistry.attachAdapter('mysql_prod', adapter)
|
|
357
|
-
|
|
358
|
-
// 3) Register schema and run CRUD
|
|
359
|
-
const sm = schema(conRegistry)
|
|
360
|
-
sm.create('User')
|
|
361
|
-
.use({ connection: 'mysql_prod', collection: 'users' })
|
|
362
|
-
.setStructure({
|
|
363
|
-
id: 'string',
|
|
364
|
-
email: 'string',
|
|
365
|
-
name: 'string editable',
|
|
366
|
-
createdAt: 'date',
|
|
367
|
-
'?field': 'allow-undefined',
|
|
368
|
-
})
|
|
369
|
-
|
|
370
|
-
const User = sm.use('User')
|
|
371
|
-
await User.add({ id: 'u_1', email: 'alice@example.com', name: 'Alice', createdAt: new Date() })
|
|
372
|
-
await User.where(['id', 'u_1']).to({ name: 'Alice Cooper' }).updateOne()
|
|
373
|
-
const one = await User.where(['id', 'u_1']).getOne()
|
|
374
|
-
await User.where(['id', 'u_1']).deleteOne()
|
|
375
|
-
|
|
376
|
-
## Connections DSL
|
|
377
|
-
|
|
378
|
-
You can define connections in a simple DSL and load them at runtime.
|
|
379
|
-
|
|
380
|
-
`connections.dsl` example:
|
|
381
|
-
|
|
382
|
-
```
|
|
383
|
-
connections = [
|
|
384
|
-
mysql_prod = [
|
|
385
|
-
type: mysql,
|
|
386
|
-
host: 127.0.0.1,
|
|
387
|
-
port: 3306,
|
|
388
|
-
user: root,
|
|
389
|
-
password: "s3cr3t",
|
|
390
|
-
database: appdb,
|
|
391
|
-
],
|
|
392
|
-
|
|
393
|
-
mongo_dev = [
|
|
394
|
-
type: mongodb,
|
|
395
|
-
uri: "mongodb://127.0.0.1:27017",
|
|
396
|
-
database: devdb,
|
|
397
|
-
],
|
|
398
|
-
]
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
Load and normalize:
|
|
402
|
-
|
|
403
|
-
```ts
|
|
404
|
-
import { parseConnectionsDsl, toNormalizedConnections, connection, schema } from '@neupgroup/mapper'
|
|
405
|
-
|
|
406
|
-
const text = await fs.promises.readFile('connections.dsl', 'utf8')
|
|
407
|
-
const envMap = parseConnectionsDsl(text)
|
|
408
|
-
const conns = toNormalizedConnections(envMap)
|
|
409
|
-
|
|
410
|
-
const conRegistry = connection()
|
|
411
|
-
for (const c of conns) {
|
|
412
|
-
conRegistry.register({ name: c.name, type: c.type, key: c.key })
|
|
413
|
-
}
|
|
414
|
-
const sm = schema(conRegistry)
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
Notes:
|
|
418
|
-
- `type` (or `dbType`) defaults to `api` if omitted.
|
|
419
|
-
- Values can be quoted or unquoted; `#` comments are ignored.
|
|
420
|
-
|
|
421
|
-
## Adapters
|
|
422
|
-
|
|
423
|
-
Adapters implement backend-specific operations. Shape:
|
|
424
|
-
|
|
425
|
-
```ts
|
|
426
|
-
export interface DbAdapter {
|
|
427
|
-
get?(options: QueryOptions): Promise<any[]>
|
|
428
|
-
getOne?(options: QueryOptions): Promise<any | null>
|
|
429
|
-
getDocuments(options: QueryOptions): Promise<any[]>
|
|
430
|
-
addDocument(collectionName: string, data: Record<string, any>): Promise<string>
|
|
431
|
-
updateDocument(collectionName: string, docId: string, data: Record<string, any>): Promise<void>
|
|
432
|
-
deleteDocument(collectionName: string, docId: string): Promise<void>
|
|
433
|
-
}
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
Attach to a connection with `conRegistry.attachAdapter('<name>', adapter)` before querying.
|
|
437
|
-
|
|
438
|
-
## Schemas & Structure
|
|
439
|
-
|
|
440
|
-
Define schemas with a descriptor object or explicit fields array:
|
|
441
|
-
|
|
442
|
-
```ts
|
|
443
|
-
sm.create('Product')
|
|
444
|
-
.use({ connection: 'mysql_prod', collection: 'products' })
|
|
445
|
-
.setStructure({
|
|
446
|
-
id: 'string',
|
|
447
|
-
title: 'string editable',
|
|
448
|
-
price: 'number',
|
|
449
|
-
createdAt: 'date',
|
|
450
|
-
'?field': 'allow-undefined',
|
|
451
|
-
})
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
Field tokens:
|
|
455
|
-
- `type`: one of `string`, `number`, `boolean`, `date`, `int`.
|
|
456
|
-
- `editable`: marks commonly modified fields.
|
|
457
|
-
- `'?field'`: enables accepting fields not listed in the schema.
|
|
458
|
-
|
|
459
|
-
## Query & CRUD
|
|
460
|
-
|
|
461
|
-
Build queries and run operations:
|
|
462
|
-
|
|
463
|
-
```ts
|
|
464
|
-
const Q = sm.use('Product')
|
|
465
|
-
await Q.add({ id: 'p_1', title: 'Widget', price: 9.99 })
|
|
466
|
-
const items = await Q.where('price', 10, '<').get()
|
|
467
|
-
const one = await Q.where(['id', 'p_1']).getOne()
|
|
468
|
-
await Q.where(['id', 'p_1']).to({ price: 7.99 }).updateOne()
|
|
469
|
-
await Q.where(['id', 'p_1']).deleteOne()
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
Methods:
|
|
473
|
-
- `where(field, value, operator?)`, `where([field, value])` and `whereComplex(raw)`.
|
|
474
|
-
- `get`, `getOne`, `add`, `delete`, `deleteOne`, `to(update).update`, `updateOne`.
|
|
475
|
-
|
|
476
|
-
## Documentation Helpers
|
|
477
|
-
|
|
478
|
-
For apps that want to render built-in documentation:
|
|
479
|
-
|
|
480
|
-
```ts
|
|
481
|
-
import { documentationMd, markdownToHtml, getDocumentationHtml } from '@neupgroup/mapper'
|
|
482
|
-
|
|
483
|
-
const html = getDocumentationHtml()
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
## API Reference
|
|
487
|
-
|
|
488
|
-
### **Core Functions**
|
|
489
|
-
- `connection()` → create connections registry (see `src/index.ts:299`–`301`)
|
|
490
|
-
- `schema(conns?)` → create `SchemaManager` (see `src/index.ts:303`–`306`)
|
|
491
|
-
- `schemas` → singleton `SchemaManager` (see `src/index.ts:308`–`311`)
|
|
492
|
-
- `createOrm(adapter)` → wrapper around a `DbAdapter` (see `src/orm/index.ts:3`–`27`)
|
|
493
|
-
- `parseConnectionsDsl(text)`, `toNormalizedConnections(map)` (see `src/env.ts:31`–`75`, `87`–`95`)
|
|
494
|
-
- `documentationMd`, `markdownToHtml`, `getDocumentationHtml` (see `src/docs.ts:5`–`275`, `277`–`356`)
|
|
495
|
-
|
|
496
|
-
### **Configuration-Based API**
|
|
497
|
-
- `createConfigMapper(config)` → Create mapper from configuration object
|
|
498
|
-
- `createDefaultMapper()` → Create mapper with default configuration
|
|
499
|
-
- `ConfigBasedMapper` → Class for configuration-based mapping
|
|
500
|
-
- `configure(config)` → Configure the mapper
|
|
501
|
-
- `makeConnection(name, type, config)` → Add connection
|
|
502
|
-
- `useConnection(name)` → Use specific connection
|
|
503
|
-
- `getConnection(name)` → Get connection details
|
|
504
|
-
|
|
505
|
-
### **Fluent API (StaticMapper)**
|
|
506
|
-
- `StaticMapper.makeConnection(name, type, config)` → Create persistent connection
|
|
507
|
-
- `StaticMapper.useConnection(name)` → Use existing connection
|
|
508
|
-
- `StaticMapper.makeTempConnection(type, config)` → Create temporary connection
|
|
509
|
-
- `StaticMapper.getConnection(name)` → Get connection by name
|
|
510
|
-
- `StaticMapper.listConnections()` → List all connections
|
|
511
|
-
|
|
512
|
-
### **Query Builder Methods**
|
|
513
|
-
- `table(name)` / `collection(name)` → Specify table/collection
|
|
514
|
-
- `select()` / `find()` → Start select query
|
|
515
|
-
- `where(field, value, operator?)` → Add where condition
|
|
516
|
-
- `orderBy(field, direction?)` → Add ordering
|
|
517
|
-
- `limit(count)` → Limit results
|
|
518
|
-
- `execute()` → Execute query
|
|
519
|
-
- `add(data)` → Insert data
|
|
520
|
-
- `update(data)` → Update data
|
|
521
|
-
- `delete()` → Delete data
|
|
522
|
-
|
|
523
|
-
### **Types**
|
|
524
|
-
- `DbAdapter`, `QueryOptions`, `EnvDslConnections`, `NormalizedConnection`
|
|
525
|
-
- `ConnectionConfig`, `MapperConfig`, `FluentConnectionBuilder`
|
|
526
|
-
- `ConnectionType`: `'sql' | 'mysql' | 'postgres' | 'mongodb' | 'firestore' | 'api'`
|
|
527
|
-
|
|
528
|
-
## Build & Local Development
|
|
529
|
-
|
|
530
|
-
```bash
|
|
531
|
-
npm run build
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
Outputs are generated to `dist/` with type declarations.
|
|
535
|
-
|
|
536
|
-
## Error Handling & Troubleshooting
|
|
537
|
-
|
|
538
|
-
- Wrap operations in `try/catch` and handle nulls from `getOne()`.
|
|
539
|
-
- Verify credentials and network connectivity for your backend.
|
|
540
|
-
- Ensure schema field names and types match your storage engine.
|
|
541
|
-
|
|
542
|
-
---
|
|
543
|
-
|
|
544
|
-
Copyright © Neup Group
|
|
545
|
-
|
|
546
|
-
## 🎯 Quick Reference
|
|
547
|
-
|
|
548
|
-
### **One-Import Benefits**
|
|
549
|
-
|
|
550
|
-
✅ **Zero Configuration**: Works out of the box
|
|
551
|
-
✅ **Auto-Detection**: Automatically configures from environment
|
|
552
|
-
✅ **Universal**: Works in Node.js and browsers
|
|
553
|
-
✅ **Type Safe**: Full TypeScript support
|
|
554
|
-
✅ **Progressive**: Start simple, scale to complex
|
|
555
|
-
✅ **Lightweight**: Minimal overhead, maximum performance
|
|
556
|
-
|
|
557
|
-
### **Migration from Original API**
|
|
558
|
-
|
|
559
|
-
The new `Mapper` default export is fully compatible with the original API:
|
|
560
|
-
|
|
561
|
-
```ts
|
|
562
|
-
// Old way (still works)
|
|
563
|
-
import { connection, schema } from '@neupgroup/mapper'
|
|
564
|
-
const conns = connection()
|
|
565
|
-
const sm = schema(conns)
|
|
566
|
-
|
|
567
|
-
// New way (recommended)
|
|
568
|
-
import Mapper from '@neupgroup/mapper'
|
|
569
|
-
// Mapper is pre-configured and ready to use
|
|
570
|
-
|
|
571
|
-
// Access underlying managers if needed
|
|
572
|
-
const conns = Mapper.getConnections()
|
|
573
|
-
const sm = Mapper.getSchemaManager()
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
### **Best Practices**
|
|
577
|
-
|
|
578
|
-
1. **Start with defaults**: Let Mapper auto-configure itself
|
|
579
|
-
2. **Use environment variables**: Set `DATABASE_URL` for production
|
|
580
|
-
3. **Define schemas early**: Create schemas at app startup
|
|
581
|
-
4. **Use TypeScript**: Get full type safety and IntelliSense
|
|
582
|
-
5. **Handle errors**: Wrap operations in try/catch blocks
|
|
583
|
-
|
|
584
|
-
### **Common Patterns**
|
|
585
|
-
|
|
586
|
-
```ts
|
|
587
|
-
// Pattern 1: Quick CRUD (One-Import)
|
|
588
|
-
await Mapper.add('users', data)
|
|
589
|
-
const users = await Mapper.get('users')
|
|
590
|
-
|
|
591
|
-
// Pattern 2: Configuration-Based
|
|
592
|
-
const mapper = createConfigMapper(config)
|
|
593
|
-
await mapper.useConnection('mydb').table('users').add(data)
|
|
594
|
-
|
|
595
|
-
// Pattern 3: Fluent API
|
|
596
|
-
await StaticMapper.useConnection('mydb').table('users').add(data).execute()
|
|
597
|
-
|
|
598
|
-
// Pattern 4: Complex queries
|
|
599
|
-
const results = await Mapper.use('users')
|
|
600
|
-
.where('age', 18, '>=')
|
|
601
|
-
.where('country', 'US')
|
|
602
|
-
.get()
|
|
603
|
-
|
|
604
|
-
// Pattern 5: Batch operations
|
|
605
|
-
const users = await Mapper.get('users')
|
|
606
|
-
for (const user of users) {
|
|
607
|
-
await Mapper.update('users', { id: user.id }, { lastSeen: new Date() })
|
|
608
|
-
}
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
## 🔄 **Choosing the Right Approach**
|
|
612
|
-
|
|
613
|
-
### **When to Use Each Method**
|
|
614
|
-
|
|
615
|
-
| Approach | Best For | Example Use Case |
|
|
616
|
-
|----------|----------|------------------|
|
|
617
|
-
| **One-Import** | Quick prototyping, simple apps | `Mapper.add('users', data)` |
|
|
618
|
-
| **Configuration-Based** | Enterprise apps, multiple environments | Load from config files |
|
|
619
|
-
| **Fluent API** | Dynamic connections, runtime decisions | Create temp connections on-demand |
|
|
620
|
-
|
|
621
|
-
### **Migration Between Approaches**
|
|
622
|
-
|
|
623
|
-
```ts
|
|
624
|
-
// Start with One-Import
|
|
625
|
-
import Mapper from '@neupgroup/mapper'
|
|
626
|
-
await Mapper.add('users', { name: 'Alice' })
|
|
627
|
-
|
|
628
|
-
// Gradually move to Configuration-Based
|
|
629
|
-
import { createConfigMapper } from '@neupgroup/mapper'
|
|
630
|
-
const mapper = createConfigMapper(config)
|
|
631
|
-
await mapper.useConnection('mydb').table('users').add({ name: 'Alice' })
|
|
632
|
-
|
|
633
|
-
// Or use Fluent API for dynamic scenarios
|
|
634
|
-
import { StaticMapper } from '@neupgroup/mapper'
|
|
635
|
-
StaticMapper.makeConnection('temp', 'mysql', config)
|
|
636
|
-
await StaticMapper.useConnection('temp').table('users').add({ name: 'Alice' })
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
### **Real-World Examples**
|
|
640
|
-
|
|
641
|
-
**Microservices Configuration:**
|
|
642
|
-
```ts
|
|
643
|
-
// config/mapper.config.ts
|
|
644
|
-
export const mapperConfig = {
|
|
645
|
-
connections: [
|
|
646
|
-
['user-service', 'postgres', 'user', 'users_db', 'user-db.internal', 5432],
|
|
647
|
-
['order-service', 'mysql', 'order', 'orders_db', 'order-db.internal', 3306],
|
|
648
|
-
['analytics-api', 'api', 'https://analytics.internal.company.com']
|
|
649
|
-
]
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
// services/UserService.ts
|
|
653
|
-
import { createConfigMapper } from '@neupgroup/mapper'
|
|
654
|
-
import { mapperConfig } from '../config/mapper.config'
|
|
655
|
-
|
|
656
|
-
const mapper = createConfigMapper(mapperConfig)
|
|
657
|
-
|
|
658
|
-
export class UserService {
|
|
659
|
-
async getUser(id: string) {
|
|
660
|
-
return await mapper.useConnection('user-service')
|
|
661
|
-
.table('users')
|
|
662
|
-
.select()
|
|
663
|
-
.where('id', id)
|
|
664
|
-
.execute()
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
**Dynamic Connection Management:**
|
|
670
|
-
```ts
|
|
671
|
-
// utils/ConnectionManager.ts
|
|
672
|
-
import { StaticMapper } from '@neupgroup/mapper'
|
|
673
|
-
|
|
674
|
-
export class ConnectionManager {
|
|
675
|
-
private activeConnections: Set<string> = new Set()
|
|
676
|
-
|
|
677
|
-
async createTenantConnection(tenantId: string, dbConfig: any) {
|
|
678
|
-
const connectionName = `tenant-${tenantId}`
|
|
679
|
-
|
|
680
|
-
StaticMapper.makeConnection(connectionName, 'mysql', {
|
|
681
|
-
host: dbConfig.host,
|
|
682
|
-
database: `tenant_${tenantId}`,
|
|
683
|
-
user: dbConfig.user,
|
|
684
|
-
password: dbConfig.password
|
|
685
|
-
})
|
|
686
|
-
|
|
687
|
-
this.activeConnections.add(connectionName)
|
|
688
|
-
return connectionName
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
async queryTenant(tenantId: string, table: string) {
|
|
692
|
-
const connectionName = `tenant-${tenantId}`
|
|
693
|
-
return await StaticMapper.useConnection(connectionName)
|
|
694
|
-
.table(table)
|
|
695
|
-
.select()
|
|
696
|
-
.execute()
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
cleanupConnection(tenantId: string) {
|
|
700
|
-
const connectionName = `tenant-${tenantId}`
|
|
701
|
-
this.activeConnections.delete(connectionName)
|
|
702
|
-
// Connection cleanup handled automatically
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
```
|
|
706
|
-
|
|
5
|
+
Please navigate to the [readme](./readme) directory to find detailed guides and chapters on how to use this package.
|