@memberjunction/metadata-sync 2.47.0 → 2.48.0
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 +217 -15
- package/dist/commands/pull/index.d.ts +90 -5
- package/dist/commands/pull/index.js +930 -118
- package/dist/commands/pull/index.js.map +1 -1
- package/dist/commands/push/index.js +18 -10
- package/dist/commands/push/index.js.map +1 -1
- package/dist/commands/status/index.js +18 -7
- package/dist/commands/status/index.js.map +1 -1
- package/dist/commands/watch/index.js +19 -6
- package/dist/commands/watch/index.js.map +1 -1
- package/dist/config.d.ts +69 -0
- package/dist/config.js +2 -13
- package/dist/config.js.map +1 -1
- package/dist/hooks/init.js +3 -0
- package/dist/hooks/init.js.map +1 -1
- package/dist/lib/config-manager.d.ts +56 -0
- package/dist/lib/config-manager.js +104 -0
- package/dist/lib/config-manager.js.map +1 -0
- package/dist/lib/provider-utils.js +45 -26
- package/dist/lib/provider-utils.js.map +1 -1
- package/dist/lib/singleton-manager.d.ts +34 -0
- package/dist/lib/singleton-manager.js +62 -0
- package/dist/lib/singleton-manager.js.map +1 -0
- package/oclif.manifest.json +50 -43
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -104,10 +104,24 @@ The tool uses a hierarchical directory structure with cascading defaults:
|
|
|
104
104
|
- Each top-level directory represents an entity type
|
|
105
105
|
- `.mj-sync.json` files define entities and base defaults
|
|
106
106
|
- `.mj-folder.json` files define folder-specific defaults (optional)
|
|
107
|
-
-
|
|
107
|
+
- Only dot-prefixed JSON files (e.g., `.prompt-template.json`, `.category.json`) are treated as metadata records
|
|
108
|
+
- Regular JSON files without the dot prefix are ignored, allowing package.json and other config files to coexist
|
|
108
109
|
- External files (`.md`, `.html`, etc.) are referenced from the JSON files
|
|
109
110
|
- Defaults cascade down through the folder hierarchy
|
|
110
111
|
|
|
112
|
+
### File Naming Convention
|
|
113
|
+
|
|
114
|
+
**Metadata files must be prefixed with a dot (.)** to be recognized by the sync tool. This convention:
|
|
115
|
+
- Clearly distinguishes metadata files from regular configuration files
|
|
116
|
+
- Allows `package.json`, `tsconfig.json` and other standard files to coexist without being processed
|
|
117
|
+
- Follows established patterns like `.gitignore` and `.eslintrc.json`
|
|
118
|
+
|
|
119
|
+
Examples:
|
|
120
|
+
- ✅ `.greeting.json` - Will be processed as metadata
|
|
121
|
+
- ✅ `.customer-prompt.json` - Will be processed as metadata
|
|
122
|
+
- ❌ `greeting.json` - Will be ignored
|
|
123
|
+
- ❌ `package.json` - Will be ignored
|
|
124
|
+
|
|
111
125
|
### File Format Options
|
|
112
126
|
|
|
113
127
|
#### Single Record per File (Default)
|
|
@@ -147,12 +161,12 @@ metadata/
|
|
|
147
161
|
│ ├── .mj-sync.json # Defines entity: "AI Prompts"
|
|
148
162
|
│ ├── customer-service/
|
|
149
163
|
│ │ ├── .mj-folder.json # Folder metadata (CategoryID, etc.)
|
|
150
|
-
│ │ ├── greeting.json
|
|
164
|
+
│ │ ├── .greeting.json # AI Prompt record with embedded models
|
|
151
165
|
│ │ ├── greeting.prompt.md # Prompt content (referenced)
|
|
152
166
|
│ │ └── greeting.notes.md # Notes field (referenced)
|
|
153
167
|
│ └── analytics/
|
|
154
168
|
│ ├── .mj-folder.json # Folder metadata (CategoryID, etc.)
|
|
155
|
-
│ ├── daily-report.json
|
|
169
|
+
│ ├── .daily-report.json # AI Prompt record
|
|
156
170
|
│ └── daily-report.prompt.md # Prompt content (referenced)
|
|
157
171
|
├── templates/ # Reusable JSON templates
|
|
158
172
|
│ ├── standard-prompt-settings.json # Common prompt configurations
|
|
@@ -163,17 +177,17 @@ metadata/
|
|
|
163
177
|
├── .mj-sync.json # Defines entity: "Templates"
|
|
164
178
|
├── email/
|
|
165
179
|
│ ├── .mj-folder.json # Folder metadata
|
|
166
|
-
│ ├── welcome.json
|
|
180
|
+
│ ├── .welcome.json # Template record (dot-prefixed)
|
|
167
181
|
│ └── welcome.template.html # Template content (referenced)
|
|
168
182
|
└── reports/
|
|
169
183
|
├── .mj-folder.json # Folder metadata
|
|
170
|
-
├── invoice.json
|
|
184
|
+
├── .invoice.json # Template record (dot-prefixed)
|
|
171
185
|
└── invoice.template.html # Template content (referenced)
|
|
172
186
|
```
|
|
173
187
|
|
|
174
188
|
## JSON Metadata Format
|
|
175
189
|
|
|
176
|
-
### Individual Record (e.g., ai-prompts/customer-service
|
|
190
|
+
### Individual Record (e.g., ai-prompts/customer-service/.greeting.json)
|
|
177
191
|
```json
|
|
178
192
|
{
|
|
179
193
|
"fields": {
|
|
@@ -476,7 +490,7 @@ Configuration follows a hierarchical structure:
|
|
|
476
490
|
```json
|
|
477
491
|
{
|
|
478
492
|
"entity": "AI Prompts",
|
|
479
|
-
"filePattern": "
|
|
493
|
+
"filePattern": ".*.json",
|
|
480
494
|
"defaults": {
|
|
481
495
|
"TypeID": "@lookup:AI Prompt Types.Name=Chat",
|
|
482
496
|
"Temperature": 0.7,
|
|
@@ -484,11 +498,21 @@ Configuration follows a hierarchical structure:
|
|
|
484
498
|
"Status": "Active"
|
|
485
499
|
},
|
|
486
500
|
"pull": {
|
|
501
|
+
"filePattern": ".*.json",
|
|
502
|
+
"updateExistingRecords": true,
|
|
503
|
+
"createNewFileIfNotFound": true,
|
|
504
|
+
"mergeStrategy": "merge",
|
|
487
505
|
"filter": "Status = 'Active'",
|
|
506
|
+
"externalizeFields": [
|
|
507
|
+
{
|
|
508
|
+
"field": "Prompt",
|
|
509
|
+
"pattern": "@file:{Name}.prompt.md"
|
|
510
|
+
}
|
|
511
|
+
],
|
|
488
512
|
"relatedEntities": {
|
|
489
513
|
"MJ: AI Prompt Models": {
|
|
490
514
|
"entity": "MJ: AI Prompt Models",
|
|
491
|
-
"foreignKey": "
|
|
515
|
+
"foreignKey": "PromptID",
|
|
492
516
|
"filter": "Status = 'Active'"
|
|
493
517
|
}
|
|
494
518
|
}
|
|
@@ -529,26 +553,204 @@ The tool now supports managing related entities as embedded collections within p
|
|
|
529
553
|
- **Relationship Clarity**: Visual representation of data relationships
|
|
530
554
|
|
|
531
555
|
### Configuration for Pull
|
|
532
|
-
|
|
556
|
+
|
|
557
|
+
The pull command now supports smart update capabilities with extensive configuration options:
|
|
558
|
+
|
|
533
559
|
```json
|
|
534
560
|
{
|
|
535
561
|
"entity": "AI Prompts",
|
|
562
|
+
"filePattern": ".*.json",
|
|
536
563
|
"pull": {
|
|
564
|
+
"filePattern": ".*.json",
|
|
565
|
+
"createNewFileIfNotFound": true,
|
|
566
|
+
"newFileName": ".all-new.json",
|
|
567
|
+
"appendRecordsToExistingFile": true,
|
|
568
|
+
"updateExistingRecords": true,
|
|
569
|
+
"preserveFields": ["customField", "localNotes"],
|
|
570
|
+
"mergeStrategy": "merge",
|
|
571
|
+
"backupBeforeUpdate": true,
|
|
572
|
+
"filter": "Status = 'Active'",
|
|
573
|
+
"externalizeFields": [
|
|
574
|
+
{
|
|
575
|
+
"field": "TemplateText",
|
|
576
|
+
"pattern": "@file:{Name}.template.md"
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
"field": "PromptText",
|
|
580
|
+
"pattern": "@file:prompts/{Name}.prompt.md"
|
|
581
|
+
}
|
|
582
|
+
],
|
|
583
|
+
"excludeFields": ["InternalID", "TempField"],
|
|
584
|
+
"lookupFields": {
|
|
585
|
+
"CategoryID": {
|
|
586
|
+
"entity": "AI Prompt Categories",
|
|
587
|
+
"field": "Name"
|
|
588
|
+
},
|
|
589
|
+
"TypeID": {
|
|
590
|
+
"entity": "AI Prompt Types",
|
|
591
|
+
"field": "Name"
|
|
592
|
+
}
|
|
593
|
+
},
|
|
537
594
|
"relatedEntities": {
|
|
538
595
|
"MJ: AI Prompt Models": {
|
|
539
596
|
"entity": "MJ: AI Prompt Models",
|
|
540
|
-
"foreignKey": "
|
|
541
|
-
"filter": "Status = 'Active'"
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
597
|
+
"foreignKey": "PromptID",
|
|
598
|
+
"filter": "Status = 'Active'",
|
|
599
|
+
"lookupFields": {
|
|
600
|
+
"ModelID": {
|
|
601
|
+
"entity": "AI Models",
|
|
602
|
+
"field": "Name"
|
|
603
|
+
}
|
|
604
|
+
}
|
|
546
605
|
}
|
|
547
606
|
}
|
|
548
607
|
}
|
|
549
608
|
}
|
|
550
609
|
```
|
|
551
610
|
|
|
611
|
+
#### Pull Configuration Options
|
|
612
|
+
|
|
613
|
+
| Option | Type | Default | Description |
|
|
614
|
+
|--------|------|---------|-------------|
|
|
615
|
+
| `filePattern` | string | Entity filePattern | Pattern for finding existing files to update |
|
|
616
|
+
| `createNewFileIfNotFound` | boolean | true | Create files for records not found locally |
|
|
617
|
+
| `newFileName` | string | - | Filename for new records when appending (see warning below) |
|
|
618
|
+
| `appendRecordsToExistingFile` | boolean | false | Append new records to a single file |
|
|
619
|
+
| `updateExistingRecords` | boolean | true | Update existing records found in local files |
|
|
620
|
+
| `preserveFields` | string[] | [] | Fields that retain local values during updates (see detailed explanation below) |
|
|
621
|
+
| `mergeStrategy` | string | "merge" | How to merge updates: "merge", "overwrite", or "skip" |
|
|
622
|
+
| `backupBeforeUpdate` | boolean | false | Create timestamped backups before updating files |
|
|
623
|
+
| `backupDirectory` | string | ".backups" | Directory name for backup files (relative to entity directory) |
|
|
624
|
+
| `filter` | string | - | SQL WHERE clause for filtering records |
|
|
625
|
+
| `externalizeFields` | array/object | - | Fields to save as external files with optional patterns |
|
|
626
|
+
| `excludeFields` | string[] | [] | Fields to completely omit from pulled data (see detailed explanation below) |
|
|
627
|
+
| `lookupFields` | object | - | Foreign keys to convert to @lookup references |
|
|
628
|
+
| `relatedEntities` | object | - | Related entities to pull as embedded collections |
|
|
629
|
+
|
|
630
|
+
> **⚠️ Important Configuration Warning**
|
|
631
|
+
>
|
|
632
|
+
> When both `appendRecordsToExistingFile: true` and `newFileName` are set, ALL new records will be appended to the single file specified by `newFileName`, effectively ignoring the standard per-record file pattern. This can lead to unexpected file organization:
|
|
633
|
+
>
|
|
634
|
+
> ```json
|
|
635
|
+
> // This configuration will put ALL new records in .all-new.json
|
|
636
|
+
> "pull": {
|
|
637
|
+
> "appendRecordsToExistingFile": true,
|
|
638
|
+
> "newFileName": ".all-new.json" // ⚠️ Overrides individual file creation
|
|
639
|
+
> }
|
|
640
|
+
> ```
|
|
641
|
+
>
|
|
642
|
+
> **Recommended configurations:**
|
|
643
|
+
> - For individual files per record: Set `appendRecordsToExistingFile: false` (or omit it)
|
|
644
|
+
> - For grouped new records: Set both `appendRecordsToExistingFile: true` and `newFileName`
|
|
645
|
+
> - For mixed approach: Omit `newFileName` to let new records follow the standard pattern
|
|
646
|
+
|
|
647
|
+
#### Merge Strategies
|
|
648
|
+
|
|
649
|
+
- **`merge`** (default): Combines fields from database and local file, with database values taking precedence for existing fields
|
|
650
|
+
- **`overwrite`**: Completely replaces local record with database version (except preserved fields)
|
|
651
|
+
- **`skip`**: Leaves existing records unchanged, only adds new records
|
|
652
|
+
|
|
653
|
+
#### Understanding excludeFields vs preserveFields
|
|
654
|
+
|
|
655
|
+
These two configuration options serve different purposes for managing fields during pull operations:
|
|
656
|
+
|
|
657
|
+
##### excludeFields
|
|
658
|
+
- **Purpose**: Completely omit specified fields from your local files
|
|
659
|
+
- **Use Case**: Remove internal/system fields you don't want in version control
|
|
660
|
+
- **Effect**: Fields never appear in the JSON files
|
|
661
|
+
- **Example**: Excluding internal IDs, timestamps, or sensitive data
|
|
662
|
+
|
|
663
|
+
##### preserveFields
|
|
664
|
+
- **Purpose**: Protect local customizations from being overwritten during updates
|
|
665
|
+
- **Use Case**: Keep locally modified values while updating other fields
|
|
666
|
+
- **Effect**: Fields exist in files but retain their local values during pull
|
|
667
|
+
- **Example**: Preserving custom file paths, local notes, or environment-specific values
|
|
668
|
+
- **Special Behavior for @file: references**: When a preserved field contains a `@file:` reference, the tool will update the content at the existing file path rather than creating a new file with a generated name
|
|
669
|
+
|
|
670
|
+
##### Example Configuration
|
|
671
|
+
```json
|
|
672
|
+
{
|
|
673
|
+
"pull": {
|
|
674
|
+
"excludeFields": ["TemplateID", "InternalNotes", "CreatedAt"],
|
|
675
|
+
"preserveFields": ["TemplateText", "OutputExample", "LocalConfig"]
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
With this configuration:
|
|
681
|
+
- **TemplateID, InternalNotes, CreatedAt** → Never appear in local files
|
|
682
|
+
- **TemplateText, OutputExample, LocalConfig** → Keep their local values during updates
|
|
683
|
+
|
|
684
|
+
##### Common Scenario: Customized File References
|
|
685
|
+
When you customize file paths (e.g., changing `@file:templates/skip-conductor.md` to `@file:templates/conductor.md`), use `preserveFields` to protect these customizations:
|
|
686
|
+
|
|
687
|
+
```json
|
|
688
|
+
{
|
|
689
|
+
"pull": {
|
|
690
|
+
"preserveFields": ["TemplateText", "OutputExample"],
|
|
691
|
+
"externalizeFields": [
|
|
692
|
+
{
|
|
693
|
+
"field": "TemplateText",
|
|
694
|
+
"pattern": "@file:templates/{Name}.template.md"
|
|
695
|
+
}
|
|
696
|
+
]
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
This ensures your custom paths aren't overwritten when pulling updates from the database.
|
|
702
|
+
|
|
703
|
+
**How it works:**
|
|
704
|
+
1. **Without preserveFields**: Pull would create a new file using the pattern (e.g., `templates/skip-conductor.template.md`) and update the JSON to point to it
|
|
705
|
+
2. **With preserveFields**: Pull keeps your custom path (e.g., `@file:templates/conductor.md`) in the JSON and updates the content at that existing location
|
|
706
|
+
|
|
707
|
+
This is particularly useful when:
|
|
708
|
+
- You've reorganized your file structure after initial pull
|
|
709
|
+
- You've renamed files to follow your own naming conventions
|
|
710
|
+
- You want to maintain consistent paths across team members
|
|
711
|
+
|
|
712
|
+
#### Backup Configuration
|
|
713
|
+
|
|
714
|
+
When `backupBeforeUpdate` is enabled, the tool creates timestamped backups before updating existing files:
|
|
715
|
+
|
|
716
|
+
- **Backup Location**: Files are backed up to the `backupDirectory` (default: `.backups`) within the entity directory
|
|
717
|
+
- **Backup Naming**: Original filename + timestamp + `.backup` extension (e.g., `.greeting.json` → `.greeting.2024-03-15T10-30-45-123Z.backup`)
|
|
718
|
+
- **Extension**: All backup files use the `.backup` extension, preventing them from being processed by push/pull/status commands
|
|
719
|
+
- **Deduplication**: Only one backup is created per file per pull operation, even if the file contains multiple records
|
|
720
|
+
|
|
721
|
+
Example configuration:
|
|
722
|
+
```json
|
|
723
|
+
"pull": {
|
|
724
|
+
"backupBeforeUpdate": true,
|
|
725
|
+
"backupDirectory": ".backups" // Custom backup directory name
|
|
726
|
+
}
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
#### Externalize Fields Patterns
|
|
730
|
+
|
|
731
|
+
The `externalizeFields` configuration supports dynamic file naming with placeholders:
|
|
732
|
+
|
|
733
|
+
```json
|
|
734
|
+
"externalizeFields": [
|
|
735
|
+
{
|
|
736
|
+
"field": "TemplateText",
|
|
737
|
+
"pattern": "@file:{Name}.template.md"
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
"field": "SQLQuery",
|
|
741
|
+
"pattern": "@file:queries/{CategoryName}/{Name}.sql"
|
|
742
|
+
}
|
|
743
|
+
]
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
Supported placeholders:
|
|
747
|
+
- `{Name}` - The entity's name field value
|
|
748
|
+
- `{ID}` - The entity's primary key
|
|
749
|
+
- `{FieldName}` - The field being externalized
|
|
750
|
+
- `{AnyFieldName}` - Any field from the entity record
|
|
751
|
+
|
|
752
|
+
All values are sanitized for filesystem compatibility (lowercase, spaces to hyphens, special characters removed).
|
|
753
|
+
|
|
552
754
|
### Nested Related Entities
|
|
553
755
|
Support for multiple levels of nesting:
|
|
554
756
|
```json
|
|
@@ -37,6 +37,7 @@ export default class Pull extends Command {
|
|
|
37
37
|
filter: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
38
38
|
'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
39
39
|
'multi-file': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
40
|
+
verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
40
41
|
};
|
|
41
42
|
run(): Promise<void>;
|
|
42
43
|
/**
|
|
@@ -77,20 +78,36 @@ export default class Pull extends Command {
|
|
|
77
78
|
* @param targetDir - Directory where files will be saved
|
|
78
79
|
* @param entityConfig - Entity configuration with defaults and settings
|
|
79
80
|
* @param syncEngine - Sync engine for checksum calculation
|
|
81
|
+
* @param flags - Command flags
|
|
82
|
+
* @param isNewRecord - Whether this is a new record
|
|
83
|
+
* @param existingRecordData - Existing record data to preserve field selection
|
|
80
84
|
* @returns Promise resolving to formatted RecordData
|
|
81
85
|
* @private
|
|
82
86
|
*/
|
|
83
87
|
private processRecordData;
|
|
88
|
+
/**
|
|
89
|
+
* Convert a foreign key value to a @lookup reference
|
|
90
|
+
*
|
|
91
|
+
* Looks up the related record and creates a @lookup string that can be
|
|
92
|
+
* resolved during push operations.
|
|
93
|
+
*
|
|
94
|
+
* @param foreignKeyValue - The foreign key value (ID)
|
|
95
|
+
* @param targetEntity - Name of the target entity
|
|
96
|
+
* @param targetField - Field in target entity to use for lookup
|
|
97
|
+
* @param syncEngine - Sync engine instance
|
|
98
|
+
* @returns @lookup string or null if lookup fails
|
|
99
|
+
* @private
|
|
100
|
+
*/
|
|
101
|
+
private convertToLookup;
|
|
84
102
|
/**
|
|
85
103
|
* Determine if a field should be saved to an external file
|
|
86
104
|
*
|
|
87
|
-
* Checks if a field
|
|
88
|
-
*
|
|
89
|
-
* based on field name and content length.
|
|
105
|
+
* Checks if a field is configured for externalization or contains substantial
|
|
106
|
+
* text content that would be better stored in a separate file.
|
|
90
107
|
*
|
|
91
108
|
* @param fieldName - Name of the field to check
|
|
92
109
|
* @param fieldValue - Value of the field
|
|
93
|
-
* @param entityConfig - Entity configuration
|
|
110
|
+
* @param entityConfig - Entity configuration with externalization settings
|
|
94
111
|
* @returns Promise resolving to true if field should be externalized
|
|
95
112
|
* @private
|
|
96
113
|
*/
|
|
@@ -101,11 +118,14 @@ export default class Pull extends Command {
|
|
|
101
118
|
* Saves large text content to a separate file and returns the filename.
|
|
102
119
|
* Automatically determines appropriate file extension based on field name
|
|
103
120
|
* and content type (e.g., .md for prompts, .html for templates).
|
|
121
|
+
* Uses the entity's name field for the filename if available.
|
|
104
122
|
*
|
|
105
123
|
* @param targetDir - Directory to save the file
|
|
106
|
-
* @param
|
|
124
|
+
* @param record - Full record to extract name field from
|
|
125
|
+
* @param primaryKey - Primary key for filename generation fallback
|
|
107
126
|
* @param fieldName - Name of the field being externalized
|
|
108
127
|
* @param content - Content to write to the file
|
|
128
|
+
* @param entityConfig - Entity configuration
|
|
109
129
|
* @returns Promise resolving to the created filename
|
|
110
130
|
* @private
|
|
111
131
|
*/
|
|
@@ -116,6 +136,7 @@ export default class Pull extends Command {
|
|
|
116
136
|
* Creates a safe filename based on the entity's primary key values.
|
|
117
137
|
* Handles GUIDs by using first 8 characters, sanitizes special characters,
|
|
118
138
|
* and creates composite names for multi-field keys.
|
|
139
|
+
* Files are prefixed with a dot to follow the metadata file convention.
|
|
119
140
|
*
|
|
120
141
|
* @param primaryKey - Primary key fields and values
|
|
121
142
|
* @param entityConfig - Entity configuration (for future extension)
|
|
@@ -150,4 +171,68 @@ export default class Pull extends Command {
|
|
|
150
171
|
* @private
|
|
151
172
|
*/
|
|
152
173
|
private findParentField;
|
|
174
|
+
/**
|
|
175
|
+
* Find existing files in a directory matching a pattern
|
|
176
|
+
*
|
|
177
|
+
* Searches for files that match the configured file pattern, used to identify
|
|
178
|
+
* which records already exist locally for smart update functionality.
|
|
179
|
+
*
|
|
180
|
+
* @param dir - Directory to search in
|
|
181
|
+
* @param pattern - Glob pattern to match files (e.g., "*.json")
|
|
182
|
+
* @returns Promise resolving to array of file paths
|
|
183
|
+
* @private
|
|
184
|
+
*/
|
|
185
|
+
private findExistingFiles;
|
|
186
|
+
/**
|
|
187
|
+
* Load existing records from files and build a lookup map
|
|
188
|
+
*
|
|
189
|
+
* Reads all existing files and creates a map from primary key to file location,
|
|
190
|
+
* enabling efficient lookup during the update process.
|
|
191
|
+
*
|
|
192
|
+
* @param files - Array of file paths to load
|
|
193
|
+
* @param entityInfo - Entity metadata for primary key information
|
|
194
|
+
* @returns Map from primary key string to file info
|
|
195
|
+
* @private
|
|
196
|
+
*/
|
|
197
|
+
private loadExistingRecords;
|
|
198
|
+
/**
|
|
199
|
+
* Create a string lookup key from primary key values
|
|
200
|
+
*
|
|
201
|
+
* Generates a consistent string representation of primary key values
|
|
202
|
+
* for use in maps and comparisons.
|
|
203
|
+
*
|
|
204
|
+
* @param primaryKey - Primary key field names and values
|
|
205
|
+
* @returns String representation of the primary key
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
private createPrimaryKeyLookup;
|
|
209
|
+
/**
|
|
210
|
+
* Merge two record data objects based on configured strategy
|
|
211
|
+
*
|
|
212
|
+
* Combines existing and new record data according to the merge strategy:
|
|
213
|
+
* - 'overwrite': Replace all fields with new values
|
|
214
|
+
* - 'merge': Combine fields, with new values taking precedence
|
|
215
|
+
* - 'skip': Keep existing record unchanged
|
|
216
|
+
*
|
|
217
|
+
* @param existing - Existing record data
|
|
218
|
+
* @param newData - New record data from database
|
|
219
|
+
* @param strategy - Merge strategy to apply
|
|
220
|
+
* @param preserveFields - Field names that should never be overwritten
|
|
221
|
+
* @returns Merged record data
|
|
222
|
+
* @private
|
|
223
|
+
*/
|
|
224
|
+
private mergeRecords;
|
|
225
|
+
/**
|
|
226
|
+
* Create a backup of a file before updating
|
|
227
|
+
*
|
|
228
|
+
* Creates a timestamped backup copy of the file in a backup directory
|
|
229
|
+
* with the original filename, timestamp suffix, and .backup extension.
|
|
230
|
+
* The backup directory defaults to .backups but can be configured.
|
|
231
|
+
*
|
|
232
|
+
* @param filePath - Path to the file to backup
|
|
233
|
+
* @param backupDirName - Name of the backup directory (optional)
|
|
234
|
+
* @returns Promise that resolves when backup is created
|
|
235
|
+
* @private
|
|
236
|
+
*/
|
|
237
|
+
private createBackup;
|
|
153
238
|
}
|