-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmapping.zod.ts
More file actions
94 lines (78 loc) · 2.93 KB
/
mapping.zod.ts
File metadata and controls
94 lines (78 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
import { z } from 'zod';
import { SnakeCaseIdentifierSchema } from '../shared/identifiers.zod';
import { QuerySchema } from './query.zod';
/**
* Transformation Logic
* Built-in helpers for converting data during import.
*/
export const TransformType = z.enum([
'none', // Direct copy
'constant', // Use a hardcoded value
'lookup', // Resolve FK (Name -> ID)
'split', // "John Doe" -> ["John", "Doe"]
'join', // ["John", "Doe"] -> "John Doe"
'javascript', // Custom script (Review security!)
'map' // Value mapping (e.g. "Active" -> "active")
]);
/**
* Field Mapping Item
*/
export const FieldMappingSchema = z.object({
/** Source Column */
source: z.union([z.string(), z.array(z.string())]).describe('Source column header(s)'),
/** Target Field */
target: z.union([z.string(), z.array(z.string())]).describe('Target object field(s)'),
/** Transformation */
transform: TransformType.default('none'),
/** Configuration for transform */
params: z.object({
// Constant
value: z.unknown().optional(),
// Lookup
object: z.string().optional(), // Lookup Object
fromField: z.string().optional(), // Match on (e.g. "name")
toField: z.string().optional(), // Value to take (e.g. "id")
autoCreate: z.boolean().optional(), // Create if missing
// Map
valueMap: z.record(z.string(), z.unknown()).optional(), // { "Open": "draft" }
// Split/Join
separator: z.string().optional()
}).optional()
});
/**
* Data Mapping Schema
* Defines a reusable data mapping configuration for ETL operations.
*
* **NAMING CONVENTION:**
* Mapping names are machine identifiers and must be lowercase snake_case.
*
* @example Good mapping names
* - 'salesforce_to_crm'
* - 'csv_import_contacts'
* - 'api_sync_orders'
*
* @example Bad mapping names (will be rejected)
* - 'SalesforceToCRM' (PascalCase)
* - 'CSV Import' (spaces)
*/
export const MappingSchema = z.object({
/** Identity */
name: SnakeCaseIdentifierSchema.describe('Mapping unique name (lowercase snake_case)'),
label: z.string().optional(),
/** Scope */
sourceFormat: z.enum(['csv', 'json', 'xml', 'sql']).default('csv'),
targetObject: z.string().describe('Target Object Name'),
/** Column Mappings */
fieldMapping: z.array(FieldMappingSchema),
/** Upsert Logic */
mode: z.enum(['insert', 'update', 'upsert']).default('insert'),
upsertKey: z.array(z.string()).optional().describe('Fields to match for upsert (e.g. email)'),
/** Extract Logic (For Export) */
extractQuery: QuerySchema.optional().describe('Query to run for export only'),
/** Error Handling */
errorPolicy: z.enum(['skip', 'abort', 'retry']).default('skip'),
batchSize: z.number().default(1000)
});
export type Mapping = z.infer<typeof MappingSchema>;
export type FieldMapping = z.infer<typeof FieldMappingSchema>;