pocketbase-zod-schema 0.2.5 → 0.3.1
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/CHANGELOG.md +16 -0
- package/dist/cli/index.cjs +497 -298
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.js +497 -298
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +497 -298
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +497 -298
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/utils/index.d.cts +2 -2
- package/dist/cli/utils/index.d.ts +2 -2
- package/dist/{fields-YjcpBXVp.d.cts → fields-RVj26U-O.d.cts} +17 -0
- package/dist/{fields-YjcpBXVp.d.ts → fields-RVj26U-O.d.ts} +17 -0
- package/dist/index.cjs +575 -155
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +576 -144
- package/dist/index.js.map +1 -1
- package/dist/migration/analyzer.cjs +12 -2
- package/dist/migration/analyzer.cjs.map +1 -1
- package/dist/migration/analyzer.d.cts +2 -2
- package/dist/migration/analyzer.d.ts +2 -2
- package/dist/migration/analyzer.js +12 -2
- package/dist/migration/analyzer.js.map +1 -1
- package/dist/migration/diff.cjs +150 -24
- package/dist/migration/diff.cjs.map +1 -1
- package/dist/migration/diff.d.cts +4 -4
- package/dist/migration/diff.d.ts +4 -4
- package/dist/migration/diff.js +150 -24
- package/dist/migration/diff.js.map +1 -1
- package/dist/migration/generator.cjs +360 -46
- package/dist/migration/generator.cjs.map +1 -1
- package/dist/migration/generator.d.cts +59 -12
- package/dist/migration/generator.d.ts +59 -12
- package/dist/migration/generator.js +356 -47
- package/dist/migration/generator.js.map +1 -1
- package/dist/migration/index.cjs +561 -90
- package/dist/migration/index.cjs.map +1 -1
- package/dist/migration/index.d.cts +3 -3
- package/dist/migration/index.d.ts +3 -3
- package/dist/migration/index.js +561 -90
- package/dist/migration/index.js.map +1 -1
- package/dist/migration/snapshot.cjs +51 -18
- package/dist/migration/snapshot.cjs.map +1 -1
- package/dist/migration/snapshot.d.cts +2 -2
- package/dist/migration/snapshot.d.ts +2 -2
- package/dist/migration/snapshot.js +51 -18
- package/dist/migration/snapshot.js.map +1 -1
- package/dist/migration/utils/index.cjs +66 -0
- package/dist/migration/utils/index.cjs.map +1 -1
- package/dist/migration/utils/index.d.cts +39 -202
- package/dist/migration/utils/index.d.ts +39 -202
- package/dist/migration/utils/index.js +65 -1
- package/dist/migration/utils/index.js.map +1 -1
- package/dist/schema.cjs +0 -61
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +2 -86
- package/dist/schema.d.ts +2 -86
- package/dist/schema.js +1 -50
- package/dist/schema.js.map +1 -1
- package/dist/type-mapper-CZzVeDj7.d.ts +208 -0
- package/dist/type-mapper-DaBe-1ph.d.cts +208 -0
- package/dist/{types-LFBGHl9Y.d.ts → types-CUVzgZ9k.d.ts} +33 -2
- package/dist/{types-mhQXWNi3.d.cts → types-D-Fsdn_O.d.cts} +33 -2
- package/package.json +1 -1
package/dist/migration/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs3 from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
import { randomBytes } from 'crypto';
|
|
4
5
|
|
|
5
6
|
// src/migration/analyzer.ts
|
|
6
7
|
({
|
|
@@ -1558,12 +1559,22 @@ function isAuthCollection(fields) {
|
|
|
1558
1559
|
function buildFieldDefinition(fieldName, zodType) {
|
|
1559
1560
|
const fieldMetadata = extractFieldMetadata(zodType.description);
|
|
1560
1561
|
if (fieldMetadata) {
|
|
1561
|
-
|
|
1562
|
+
let required2;
|
|
1563
|
+
if (fieldMetadata.type === "number") {
|
|
1564
|
+
if (fieldMetadata.options?.required !== void 0) {
|
|
1565
|
+
required2 = fieldMetadata.options.required;
|
|
1566
|
+
} else {
|
|
1567
|
+
required2 = false;
|
|
1568
|
+
}
|
|
1569
|
+
} else {
|
|
1570
|
+
required2 = isFieldRequired(zodType);
|
|
1571
|
+
}
|
|
1572
|
+
const { required: _required, ...options2 } = fieldMetadata.options || {};
|
|
1562
1573
|
const fieldDef2 = {
|
|
1563
1574
|
name: fieldName,
|
|
1564
1575
|
type: fieldMetadata.type,
|
|
1565
1576
|
required: required2,
|
|
1566
|
-
options:
|
|
1577
|
+
options: Object.keys(options2).length > 0 ? options2 : void 0
|
|
1567
1578
|
};
|
|
1568
1579
|
if (fieldMetadata.type === "relation") {
|
|
1569
1580
|
const relationMetadata2 = extractRelationMetadata(zodType.description);
|
|
@@ -1762,7 +1773,7 @@ var SchemaAnalyzer = class {
|
|
|
1762
1773
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
1763
1774
|
function resolveCollectionIdToName(collectionId) {
|
|
1764
1775
|
if (collectionId === "_pb_users_auth_") {
|
|
1765
|
-
return "
|
|
1776
|
+
return "users";
|
|
1766
1777
|
}
|
|
1767
1778
|
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
1768
1779
|
if (nameMatch) {
|
|
@@ -1770,6 +1781,39 @@ function resolveCollectionIdToName(collectionId) {
|
|
|
1770
1781
|
}
|
|
1771
1782
|
return collectionId;
|
|
1772
1783
|
}
|
|
1784
|
+
function extractFieldOptions2(pbField) {
|
|
1785
|
+
const options = {};
|
|
1786
|
+
if (pbField.options && typeof pbField.options === "object") {
|
|
1787
|
+
Object.assign(options, pbField.options);
|
|
1788
|
+
}
|
|
1789
|
+
const directOptionKeys = [
|
|
1790
|
+
"min",
|
|
1791
|
+
"max",
|
|
1792
|
+
"pattern",
|
|
1793
|
+
"noDecimal",
|
|
1794
|
+
// text/number fields
|
|
1795
|
+
"values",
|
|
1796
|
+
"maxSelect",
|
|
1797
|
+
// select fields
|
|
1798
|
+
"mimeTypes",
|
|
1799
|
+
"maxSize",
|
|
1800
|
+
"thumbs",
|
|
1801
|
+
"protected",
|
|
1802
|
+
// file fields
|
|
1803
|
+
"onCreate",
|
|
1804
|
+
"onUpdate",
|
|
1805
|
+
// autodate fields
|
|
1806
|
+
"exceptDomains",
|
|
1807
|
+
"onlyDomains"
|
|
1808
|
+
// email/url fields
|
|
1809
|
+
];
|
|
1810
|
+
for (const key of directOptionKeys) {
|
|
1811
|
+
if (pbField[key] !== void 0) {
|
|
1812
|
+
options[key] = pbField[key];
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
return options;
|
|
1816
|
+
}
|
|
1773
1817
|
function convertPocketBaseCollection(pbCollection) {
|
|
1774
1818
|
const fields = [];
|
|
1775
1819
|
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
@@ -1787,23 +1831,19 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
1787
1831
|
type: pbField.type,
|
|
1788
1832
|
required: pbField.required || false
|
|
1789
1833
|
};
|
|
1790
|
-
field.options = pbField
|
|
1791
|
-
if (pbField.type === "select") {
|
|
1792
|
-
if (pbField.values && Array.isArray(pbField.values)) {
|
|
1793
|
-
field.options.values = pbField.values;
|
|
1794
|
-
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
1795
|
-
field.options.values = pbField.options.values;
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1834
|
+
field.options = extractFieldOptions2(pbField);
|
|
1798
1835
|
if (pbField.type === "relation") {
|
|
1799
1836
|
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
1800
|
-
const collectionName = resolveCollectionIdToName(collectionId);
|
|
1837
|
+
const collectionName = resolveCollectionIdToName(collectionId || "");
|
|
1801
1838
|
field.relation = {
|
|
1802
1839
|
collection: collectionName,
|
|
1803
1840
|
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
1804
1841
|
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
1805
1842
|
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
1806
1843
|
};
|
|
1844
|
+
delete field.options.maxSelect;
|
|
1845
|
+
delete field.options.minSelect;
|
|
1846
|
+
delete field.options.cascadeDelete;
|
|
1807
1847
|
}
|
|
1808
1848
|
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
1809
1849
|
if (Object.keys(field.options).length === 0) {
|
|
@@ -1817,17 +1857,21 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
1817
1857
|
type: pbCollection.type || "base",
|
|
1818
1858
|
fields
|
|
1819
1859
|
};
|
|
1860
|
+
if (pbCollection.id) {
|
|
1861
|
+
schema.id = pbCollection.id;
|
|
1862
|
+
}
|
|
1820
1863
|
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
1821
1864
|
schema.indexes = pbCollection.indexes;
|
|
1822
1865
|
}
|
|
1823
|
-
const
|
|
1824
|
-
if (
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1866
|
+
const hasAnyRule = pbCollection.listRule !== void 0 || pbCollection.viewRule !== void 0 || pbCollection.createRule !== void 0 || pbCollection.updateRule !== void 0 || pbCollection.deleteRule !== void 0 || pbCollection.manageRule !== void 0;
|
|
1867
|
+
if (hasAnyRule) {
|
|
1868
|
+
const rules = {};
|
|
1869
|
+
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
1870
|
+
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
1871
|
+
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
1872
|
+
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
1873
|
+
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
1874
|
+
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
1831
1875
|
schema.rules = rules;
|
|
1832
1876
|
schema.permissions = { ...rules };
|
|
1833
1877
|
}
|
|
@@ -2559,6 +2603,67 @@ var SnapshotManager = class {
|
|
|
2559
2603
|
return validateSnapshot(snapshot);
|
|
2560
2604
|
}
|
|
2561
2605
|
};
|
|
2606
|
+
function generateCollectionId() {
|
|
2607
|
+
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
2608
|
+
const idLength = 15;
|
|
2609
|
+
const bytes = randomBytes(idLength);
|
|
2610
|
+
let id = "pb_";
|
|
2611
|
+
for (let i = 0; i < idLength; i++) {
|
|
2612
|
+
const index = bytes[i] % chars.length;
|
|
2613
|
+
id += chars[index];
|
|
2614
|
+
}
|
|
2615
|
+
return id;
|
|
2616
|
+
}
|
|
2617
|
+
var CollectionIdRegistry = class {
|
|
2618
|
+
ids;
|
|
2619
|
+
constructor() {
|
|
2620
|
+
this.ids = /* @__PURE__ */ new Set();
|
|
2621
|
+
}
|
|
2622
|
+
/**
|
|
2623
|
+
* Generates a unique collection ID for a given collection name
|
|
2624
|
+
* Retries up to 10 times if collision occurs (extremely rare)
|
|
2625
|
+
* Special case: returns "_pb_users_auth_" for users collection
|
|
2626
|
+
*
|
|
2627
|
+
* @param collectionName - The name of the collection (optional)
|
|
2628
|
+
* @returns A unique collection ID
|
|
2629
|
+
* @throws Error if unable to generate unique ID after max attempts
|
|
2630
|
+
*/
|
|
2631
|
+
generate(collectionName) {
|
|
2632
|
+
if (collectionName && collectionName.toLowerCase() === "users") {
|
|
2633
|
+
const usersId = "_pb_users_auth_";
|
|
2634
|
+
if (!this.has(usersId)) {
|
|
2635
|
+
this.register(usersId);
|
|
2636
|
+
}
|
|
2637
|
+
return usersId;
|
|
2638
|
+
}
|
|
2639
|
+
const maxAttempts = 10;
|
|
2640
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
2641
|
+
const id = generateCollectionId();
|
|
2642
|
+
if (!this.has(id)) {
|
|
2643
|
+
this.register(id);
|
|
2644
|
+
return id;
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
throw new Error("Failed to generate unique collection ID after maximum attempts");
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Checks if an ID has already been registered
|
|
2651
|
+
*
|
|
2652
|
+
* @param id - The collection ID to check
|
|
2653
|
+
* @returns True if the ID exists in the registry
|
|
2654
|
+
*/
|
|
2655
|
+
has(id) {
|
|
2656
|
+
return this.ids.has(id);
|
|
2657
|
+
}
|
|
2658
|
+
/**
|
|
2659
|
+
* Registers a collection ID in the registry
|
|
2660
|
+
*
|
|
2661
|
+
* @param id - The collection ID to register
|
|
2662
|
+
*/
|
|
2663
|
+
register(id) {
|
|
2664
|
+
this.ids.add(id);
|
|
2665
|
+
}
|
|
2666
|
+
};
|
|
2562
2667
|
|
|
2563
2668
|
// src/migration/diff.ts
|
|
2564
2669
|
var DEFAULT_CONFIG3 = {
|
|
@@ -2712,18 +2817,49 @@ function compareFieldConstraints(currentField, previousField) {
|
|
|
2712
2817
|
}
|
|
2713
2818
|
return changes;
|
|
2714
2819
|
}
|
|
2820
|
+
function normalizeOptionValue(key, value, fieldType) {
|
|
2821
|
+
if (key === "maxSelect" && value === 1 && (fieldType === "select" || fieldType === "file")) {
|
|
2822
|
+
return void 0;
|
|
2823
|
+
}
|
|
2824
|
+
if (key === "maxSize" && value === 0 && fieldType === "file") {
|
|
2825
|
+
return void 0;
|
|
2826
|
+
}
|
|
2827
|
+
if (fieldType === "file") {
|
|
2828
|
+
if (key === "mimeTypes" && Array.isArray(value) && value.length === 0) {
|
|
2829
|
+
return void 0;
|
|
2830
|
+
}
|
|
2831
|
+
if (key === "thumbs" && Array.isArray(value) && value.length === 0) {
|
|
2832
|
+
return void 0;
|
|
2833
|
+
}
|
|
2834
|
+
if (key === "protected" && value === false) {
|
|
2835
|
+
return void 0;
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
if (fieldType === "autodate") {
|
|
2839
|
+
if (key === "onCreate" && value === true) {
|
|
2840
|
+
return void 0;
|
|
2841
|
+
}
|
|
2842
|
+
if (key === "onUpdate" && value === false) {
|
|
2843
|
+
return void 0;
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
return value;
|
|
2847
|
+
}
|
|
2715
2848
|
function compareFieldOptions(currentField, previousField) {
|
|
2716
2849
|
const changes = [];
|
|
2717
2850
|
const currentOptions = currentField.options || {};
|
|
2718
2851
|
const previousOptions = previousField.options || {};
|
|
2719
2852
|
const allKeys = /* @__PURE__ */ new Set([...Object.keys(currentOptions), ...Object.keys(previousOptions)]);
|
|
2853
|
+
const fieldType = currentField.type;
|
|
2720
2854
|
for (const key of allKeys) {
|
|
2721
2855
|
const currentValue = currentOptions[key];
|
|
2722
2856
|
const previousValue = previousOptions[key];
|
|
2723
|
-
|
|
2857
|
+
const normalizedCurrent = normalizeOptionValue(key, currentValue, fieldType);
|
|
2858
|
+
const normalizedPrevious = normalizeOptionValue(key, previousValue, fieldType);
|
|
2859
|
+
if (normalizedCurrent === void 0 && normalizedPrevious === void 0) {
|
|
2724
2860
|
continue;
|
|
2725
2861
|
}
|
|
2726
|
-
if (!areValuesEqual(
|
|
2862
|
+
if (!areValuesEqual(normalizedCurrent, normalizedPrevious)) {
|
|
2727
2863
|
changes.push({
|
|
2728
2864
|
property: `options.${key}`,
|
|
2729
2865
|
oldValue: previousValue,
|
|
@@ -2733,7 +2869,7 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
2733
2869
|
}
|
|
2734
2870
|
return changes;
|
|
2735
2871
|
}
|
|
2736
|
-
function compareRelationConfigurations(currentField, previousField) {
|
|
2872
|
+
function compareRelationConfigurations(currentField, previousField, collectionIdToName) {
|
|
2737
2873
|
const changes = [];
|
|
2738
2874
|
const currentRelation = currentField.relation;
|
|
2739
2875
|
const previousRelation = previousField.relation;
|
|
@@ -2745,8 +2881,8 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2745
2881
|
}
|
|
2746
2882
|
const normalizeCollection = (collection) => {
|
|
2747
2883
|
if (!collection) return collection;
|
|
2748
|
-
if (
|
|
2749
|
-
return
|
|
2884
|
+
if (collectionIdToName && collectionIdToName.has(collection)) {
|
|
2885
|
+
return collectionIdToName.get(collection);
|
|
2750
2886
|
}
|
|
2751
2887
|
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2752
2888
|
if (nameMatch) {
|
|
@@ -2756,13 +2892,11 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2756
2892
|
};
|
|
2757
2893
|
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
2758
2894
|
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
2759
|
-
if (normalizedCurrent !== normalizedPrevious) {
|
|
2895
|
+
if (normalizedCurrent.toLowerCase() !== normalizedPrevious.toLowerCase()) {
|
|
2760
2896
|
changes.push({
|
|
2761
2897
|
property: "relation.collection",
|
|
2762
|
-
oldValue:
|
|
2763
|
-
|
|
2764
|
-
newValue: normalizedCurrent
|
|
2765
|
-
// Use normalized value for clarity
|
|
2898
|
+
oldValue: previousRelation.collection,
|
|
2899
|
+
newValue: currentRelation.collection
|
|
2766
2900
|
});
|
|
2767
2901
|
}
|
|
2768
2902
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -2772,14 +2906,20 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2772
2906
|
newValue: currentRelation.cascadeDelete
|
|
2773
2907
|
});
|
|
2774
2908
|
}
|
|
2775
|
-
|
|
2909
|
+
const normalizeMax = (val) => val === 1 ? null : val;
|
|
2910
|
+
const currentMax = normalizeMax(currentRelation.maxSelect);
|
|
2911
|
+
const previousMax = normalizeMax(previousRelation.maxSelect);
|
|
2912
|
+
if (currentMax != previousMax) {
|
|
2776
2913
|
changes.push({
|
|
2777
2914
|
property: "relation.maxSelect",
|
|
2778
2915
|
oldValue: previousRelation.maxSelect,
|
|
2779
2916
|
newValue: currentRelation.maxSelect
|
|
2780
2917
|
});
|
|
2781
2918
|
}
|
|
2782
|
-
|
|
2919
|
+
const normalizeMin = (val) => val === 0 ? null : val;
|
|
2920
|
+
const currentMin = normalizeMin(currentRelation.minSelect);
|
|
2921
|
+
const previousMin = normalizeMin(previousRelation.minSelect);
|
|
2922
|
+
if (currentMin != previousMin) {
|
|
2783
2923
|
changes.push({
|
|
2784
2924
|
property: "relation.minSelect",
|
|
2785
2925
|
oldValue: previousRelation.minSelect,
|
|
@@ -2788,7 +2928,7 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
2788
2928
|
}
|
|
2789
2929
|
return changes;
|
|
2790
2930
|
}
|
|
2791
|
-
function detectFieldChanges(currentField, previousField) {
|
|
2931
|
+
function detectFieldChanges(currentField, previousField, collectionIdToName) {
|
|
2792
2932
|
const changes = [];
|
|
2793
2933
|
const typeChange = compareFieldTypes(currentField, previousField);
|
|
2794
2934
|
if (typeChange) {
|
|
@@ -2797,7 +2937,7 @@ function detectFieldChanges(currentField, previousField) {
|
|
|
2797
2937
|
changes.push(...compareFieldConstraints(currentField, previousField));
|
|
2798
2938
|
changes.push(...compareFieldOptions(currentField, previousField));
|
|
2799
2939
|
if (currentField.type === "relation" && previousField.type === "relation") {
|
|
2800
|
-
changes.push(...compareRelationConfigurations(currentField, previousField));
|
|
2940
|
+
changes.push(...compareRelationConfigurations(currentField, previousField, collectionIdToName));
|
|
2801
2941
|
}
|
|
2802
2942
|
return changes;
|
|
2803
2943
|
}
|
|
@@ -2808,7 +2948,7 @@ function compareIndexes(currentIndexes = [], previousIndexes = []) {
|
|
|
2808
2948
|
const indexesToRemove = previousIndexes.filter((idx) => !currentSet.has(idx));
|
|
2809
2949
|
return { indexesToAdd, indexesToRemove };
|
|
2810
2950
|
}
|
|
2811
|
-
function compareRules(currentRules, previousRules) {
|
|
2951
|
+
function compareRules(currentRules, previousRules, currentPermissions, previousPermissions) {
|
|
2812
2952
|
const updates = [];
|
|
2813
2953
|
const ruleTypes = [
|
|
2814
2954
|
"listRule",
|
|
@@ -2819,8 +2959,8 @@ function compareRules(currentRules, previousRules) {
|
|
|
2819
2959
|
"manageRule"
|
|
2820
2960
|
];
|
|
2821
2961
|
for (const ruleType of ruleTypes) {
|
|
2822
|
-
const currentValue = currentRules?.[ruleType] ?? null;
|
|
2823
|
-
const previousValue = previousRules?.[ruleType] ?? null;
|
|
2962
|
+
const currentValue = currentRules?.[ruleType] ?? currentPermissions?.[ruleType] ?? null;
|
|
2963
|
+
const previousValue = previousRules?.[ruleType] ?? previousPermissions?.[ruleType] ?? null;
|
|
2824
2964
|
if (currentValue !== previousValue) {
|
|
2825
2965
|
updates.push({
|
|
2826
2966
|
ruleType,
|
|
@@ -2847,7 +2987,7 @@ function comparePermissions(currentPermissions, previousPermissions) {
|
|
|
2847
2987
|
}
|
|
2848
2988
|
return changes;
|
|
2849
2989
|
}
|
|
2850
|
-
function compareCollectionFields(currentCollection, previousCollection, config) {
|
|
2990
|
+
function compareCollectionFields(currentCollection, previousCollection, config, collectionIdToName) {
|
|
2851
2991
|
let fieldsToAdd = findNewFields(currentCollection.fields, previousCollection.fields);
|
|
2852
2992
|
const fieldsToRemove = findRemovedFields(currentCollection.fields, previousCollection.fields);
|
|
2853
2993
|
const fieldsToModify = [];
|
|
@@ -2857,7 +2997,7 @@ function compareCollectionFields(currentCollection, previousCollection, config)
|
|
|
2857
2997
|
}
|
|
2858
2998
|
const matchedFields = matchFieldsByName(currentCollection.fields, previousCollection.fields);
|
|
2859
2999
|
for (const [currentField, previousField] of matchedFields) {
|
|
2860
|
-
const changes = detectFieldChanges(currentField, previousField);
|
|
3000
|
+
const changes = detectFieldChanges(currentField, previousField, collectionIdToName);
|
|
2861
3001
|
if (changes.length > 0) {
|
|
2862
3002
|
fieldsToModify.push({
|
|
2863
3003
|
fieldName: currentField.name,
|
|
@@ -2869,14 +3009,20 @@ function compareCollectionFields(currentCollection, previousCollection, config)
|
|
|
2869
3009
|
}
|
|
2870
3010
|
return { fieldsToAdd, fieldsToRemove, fieldsToModify };
|
|
2871
3011
|
}
|
|
2872
|
-
function buildCollectionModification(currentCollection, previousCollection, config) {
|
|
3012
|
+
function buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName) {
|
|
2873
3013
|
const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(
|
|
2874
3014
|
currentCollection,
|
|
2875
3015
|
previousCollection,
|
|
2876
|
-
config
|
|
3016
|
+
config,
|
|
3017
|
+
collectionIdToName
|
|
2877
3018
|
);
|
|
2878
3019
|
const { indexesToAdd, indexesToRemove } = compareIndexes(currentCollection.indexes, previousCollection.indexes);
|
|
2879
|
-
const rulesToUpdate = compareRules(
|
|
3020
|
+
const rulesToUpdate = compareRules(
|
|
3021
|
+
currentCollection.rules,
|
|
3022
|
+
previousCollection.rules,
|
|
3023
|
+
currentCollection.permissions,
|
|
3024
|
+
previousCollection.permissions
|
|
3025
|
+
);
|
|
2880
3026
|
const permissionsToUpdate = comparePermissions(currentCollection.permissions, previousCollection.permissions);
|
|
2881
3027
|
return {
|
|
2882
3028
|
collection: currentCollection.name,
|
|
@@ -2893,6 +3039,14 @@ function hasChanges(modification) {
|
|
|
2893
3039
|
return modification.fieldsToAdd.length > 0 || modification.fieldsToRemove.length > 0 || modification.fieldsToModify.length > 0 || modification.indexesToAdd.length > 0 || modification.indexesToRemove.length > 0 || modification.rulesToUpdate.length > 0 || modification.permissionsToUpdate.length > 0;
|
|
2894
3040
|
}
|
|
2895
3041
|
function aggregateChanges(currentSchema, previousSnapshot, config) {
|
|
3042
|
+
const collectionIdToName = /* @__PURE__ */ new Map();
|
|
3043
|
+
if (previousSnapshot) {
|
|
3044
|
+
for (const [name, collection] of previousSnapshot.collections) {
|
|
3045
|
+
if (collection.id) {
|
|
3046
|
+
collectionIdToName.set(collection.id, name);
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
2896
3050
|
const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);
|
|
2897
3051
|
const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);
|
|
2898
3052
|
const filteredCollectionsToCreate = collectionsToCreate.filter(
|
|
@@ -2901,16 +3055,28 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
|
|
|
2901
3055
|
const filteredCollectionsToDelete = collectionsToDelete.filter(
|
|
2902
3056
|
(collection) => !isSystemCollection(collection.name, config)
|
|
2903
3057
|
);
|
|
3058
|
+
const registry = new CollectionIdRegistry();
|
|
3059
|
+
const collectionsWithIds = filteredCollectionsToCreate.map((collection) => {
|
|
3060
|
+
if (collection.id) {
|
|
3061
|
+
registry.register(collection.id);
|
|
3062
|
+
return collection;
|
|
3063
|
+
}
|
|
3064
|
+
const id = registry.generate(collection.name);
|
|
3065
|
+
return {
|
|
3066
|
+
...collection,
|
|
3067
|
+
id
|
|
3068
|
+
};
|
|
3069
|
+
});
|
|
2904
3070
|
const collectionsToModify = [];
|
|
2905
3071
|
const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);
|
|
2906
3072
|
for (const [currentCollection, previousCollection] of matchedCollections) {
|
|
2907
|
-
const modification = buildCollectionModification(currentCollection, previousCollection, config);
|
|
3073
|
+
const modification = buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName);
|
|
2908
3074
|
if (hasChanges(modification)) {
|
|
2909
3075
|
collectionsToModify.push(modification);
|
|
2910
3076
|
}
|
|
2911
3077
|
}
|
|
2912
3078
|
return {
|
|
2913
|
-
collectionsToCreate:
|
|
3079
|
+
collectionsToCreate: collectionsWithIds,
|
|
2914
3080
|
collectionsToDelete: filteredCollectionsToDelete,
|
|
2915
3081
|
collectionsToModify
|
|
2916
3082
|
};
|
|
@@ -3146,6 +3312,49 @@ function generateTimestamp(config) {
|
|
|
3146
3312
|
}
|
|
3147
3313
|
return Math.floor(Date.now() / 1e3).toString();
|
|
3148
3314
|
}
|
|
3315
|
+
function splitDiffByCollection(diff, baseTimestamp) {
|
|
3316
|
+
const operations = [];
|
|
3317
|
+
let currentTimestamp = parseInt(baseTimestamp, 10);
|
|
3318
|
+
for (const collection of diff.collectionsToCreate) {
|
|
3319
|
+
operations.push({
|
|
3320
|
+
type: "create",
|
|
3321
|
+
collection,
|
|
3322
|
+
timestamp: currentTimestamp.toString()
|
|
3323
|
+
});
|
|
3324
|
+
currentTimestamp += 1;
|
|
3325
|
+
}
|
|
3326
|
+
for (const modification of diff.collectionsToModify) {
|
|
3327
|
+
operations.push({
|
|
3328
|
+
type: "modify",
|
|
3329
|
+
collection: modification.collection,
|
|
3330
|
+
modifications: modification,
|
|
3331
|
+
timestamp: currentTimestamp.toString()
|
|
3332
|
+
});
|
|
3333
|
+
currentTimestamp += 1;
|
|
3334
|
+
}
|
|
3335
|
+
for (const collection of diff.collectionsToDelete) {
|
|
3336
|
+
operations.push({
|
|
3337
|
+
type: "delete",
|
|
3338
|
+
collection: collection.name || collection,
|
|
3339
|
+
// Handle both object and string
|
|
3340
|
+
timestamp: currentTimestamp.toString()
|
|
3341
|
+
});
|
|
3342
|
+
currentTimestamp += 1;
|
|
3343
|
+
}
|
|
3344
|
+
return operations;
|
|
3345
|
+
}
|
|
3346
|
+
function generateCollectionMigrationFilename(operation) {
|
|
3347
|
+
const timestamp = operation.timestamp;
|
|
3348
|
+
const operationType = operation.type === "modify" ? "updated" : operation.type === "create" ? "created" : "deleted";
|
|
3349
|
+
let collectionName;
|
|
3350
|
+
if (typeof operation.collection === "string") {
|
|
3351
|
+
collectionName = operation.collection;
|
|
3352
|
+
} else {
|
|
3353
|
+
collectionName = operation.collection.name;
|
|
3354
|
+
}
|
|
3355
|
+
const sanitizedName = collectionName.replace(/[^a-zA-Z0-9_]/g, "_").toLowerCase();
|
|
3356
|
+
return `${timestamp}_${operationType}_${sanitizedName}.js`;
|
|
3357
|
+
}
|
|
3149
3358
|
function generateMigrationDescription(diff) {
|
|
3150
3359
|
const parts = [];
|
|
3151
3360
|
if (diff.collectionsToCreate.length > 0) {
|
|
@@ -3253,14 +3462,13 @@ function formatValue(value) {
|
|
|
3253
3462
|
return "null";
|
|
3254
3463
|
}
|
|
3255
3464
|
if (typeof value === "string") {
|
|
3256
|
-
return
|
|
3465
|
+
return JSON.stringify(value);
|
|
3257
3466
|
}
|
|
3258
3467
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
3259
3468
|
return String(value);
|
|
3260
3469
|
}
|
|
3261
3470
|
if (Array.isArray(value)) {
|
|
3262
|
-
|
|
3263
|
-
return `[${items}]`;
|
|
3471
|
+
return JSON.stringify(value).replace(/","/g, '", "');
|
|
3264
3472
|
}
|
|
3265
3473
|
if (typeof value === "object") {
|
|
3266
3474
|
const entries = Object.entries(value).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
|
|
@@ -3268,7 +3476,7 @@ function formatValue(value) {
|
|
|
3268
3476
|
}
|
|
3269
3477
|
return String(value);
|
|
3270
3478
|
}
|
|
3271
|
-
function generateFieldDefinitionObject(field) {
|
|
3479
|
+
function generateFieldDefinitionObject(field, collectionIdMap) {
|
|
3272
3480
|
const parts = [];
|
|
3273
3481
|
parts.push(` name: "${field.name}"`);
|
|
3274
3482
|
parts.push(` type: "${field.type}"`);
|
|
@@ -3276,34 +3484,47 @@ function generateFieldDefinitionObject(field) {
|
|
|
3276
3484
|
if (field.unique !== void 0) {
|
|
3277
3485
|
parts.push(` unique: ${field.unique}`);
|
|
3278
3486
|
}
|
|
3487
|
+
if (field.type === "select") {
|
|
3488
|
+
const maxSelect = field.options?.maxSelect ?? 1;
|
|
3489
|
+
parts.push(` maxSelect: ${maxSelect}`);
|
|
3490
|
+
const values = field.options?.values ?? [];
|
|
3491
|
+
parts.push(` values: ${formatValue(values)}`);
|
|
3492
|
+
}
|
|
3279
3493
|
if (field.options && Object.keys(field.options).length > 0) {
|
|
3280
3494
|
for (const [key, value] of Object.entries(field.options)) {
|
|
3495
|
+
if (field.type === "select" && (key === "maxSelect" || key === "values")) {
|
|
3496
|
+
continue;
|
|
3497
|
+
}
|
|
3281
3498
|
parts.push(` ${key}: ${formatValue(value)}`);
|
|
3282
3499
|
}
|
|
3283
3500
|
}
|
|
3284
3501
|
if (field.relation) {
|
|
3285
3502
|
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
}
|
|
3294
|
-
if (field.relation.cascadeDelete !== void 0) {
|
|
3295
|
-
parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
|
|
3503
|
+
let collectionIdValue;
|
|
3504
|
+
if (isUsersCollection) {
|
|
3505
|
+
collectionIdValue = '"_pb_users_auth_"';
|
|
3506
|
+
} else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
|
|
3507
|
+
collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
|
|
3508
|
+
} else {
|
|
3509
|
+
collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
3296
3510
|
}
|
|
3511
|
+
parts.push(` collectionId: ${collectionIdValue}`);
|
|
3512
|
+
const maxSelect = field.relation.maxSelect ?? 1;
|
|
3513
|
+
parts.push(` maxSelect: ${maxSelect}`);
|
|
3514
|
+
const minSelect = field.relation.minSelect ?? null;
|
|
3515
|
+
parts.push(` minSelect: ${minSelect}`);
|
|
3516
|
+
const cascadeDelete = field.relation.cascadeDelete ?? false;
|
|
3517
|
+
parts.push(` cascadeDelete: ${cascadeDelete}`);
|
|
3297
3518
|
}
|
|
3298
3519
|
return ` {
|
|
3299
3520
|
${parts.join(",\n")},
|
|
3300
3521
|
}`;
|
|
3301
3522
|
}
|
|
3302
|
-
function generateFieldsArray(fields) {
|
|
3523
|
+
function generateFieldsArray(fields, collectionIdMap) {
|
|
3303
3524
|
if (fields.length === 0) {
|
|
3304
3525
|
return "[]";
|
|
3305
3526
|
}
|
|
3306
|
-
const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field));
|
|
3527
|
+
const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field, collectionIdMap));
|
|
3307
3528
|
return `[
|
|
3308
3529
|
${fieldObjects.join(",\n")},
|
|
3309
3530
|
]`;
|
|
@@ -3362,7 +3583,7 @@ function generateIndexesArray(indexes) {
|
|
|
3362
3583
|
if (!indexes || indexes.length === 0) {
|
|
3363
3584
|
return "[]";
|
|
3364
3585
|
}
|
|
3365
|
-
const indexStrings = indexes.map((idx) =>
|
|
3586
|
+
const indexStrings = indexes.map((idx) => JSON.stringify(idx));
|
|
3366
3587
|
return `[
|
|
3367
3588
|
${indexStrings.join(",\n ")},
|
|
3368
3589
|
]`;
|
|
@@ -3416,9 +3637,12 @@ function getSystemFields() {
|
|
|
3416
3637
|
}
|
|
3417
3638
|
];
|
|
3418
3639
|
}
|
|
3419
|
-
function generateCollectionCreation(collection, varName = "collection", isLast = false) {
|
|
3640
|
+
function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
|
|
3420
3641
|
const lines = [];
|
|
3421
3642
|
lines.push(` const ${varName} = new Collection({`);
|
|
3643
|
+
if (collection.id) {
|
|
3644
|
+
lines.push(` id: ${formatValue(collection.id)},`);
|
|
3645
|
+
}
|
|
3422
3646
|
lines.push(` name: "${collection.name}",`);
|
|
3423
3647
|
lines.push(` type: "${collection.type}",`);
|
|
3424
3648
|
const permissionsCode = generateCollectionPermissions(collection.permissions);
|
|
@@ -3430,7 +3654,7 @@ function generateCollectionCreation(collection, varName = "collection", isLast =
|
|
|
3430
3654
|
}
|
|
3431
3655
|
const systemFields = getSystemFields();
|
|
3432
3656
|
const allFields = [...systemFields, ...collection.fields];
|
|
3433
|
-
lines.push(` fields: ${generateFieldsArray(allFields)},`);
|
|
3657
|
+
lines.push(` fields: ${generateFieldsArray(allFields, collectionIdMap)},`);
|
|
3434
3658
|
lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
|
|
3435
3659
|
lines.push(` });`);
|
|
3436
3660
|
lines.push(``);
|
|
@@ -3452,42 +3676,59 @@ function getFieldConstructorName(fieldType) {
|
|
|
3452
3676
|
};
|
|
3453
3677
|
return constructorMap[fieldType] || "TextField";
|
|
3454
3678
|
}
|
|
3455
|
-
function generateFieldConstructorOptions(field) {
|
|
3679
|
+
function generateFieldConstructorOptions(field, collectionIdMap) {
|
|
3456
3680
|
const parts = [];
|
|
3457
3681
|
parts.push(` name: "${field.name}"`);
|
|
3458
3682
|
parts.push(` required: ${field.required}`);
|
|
3459
3683
|
if (field.unique !== void 0) {
|
|
3460
3684
|
parts.push(` unique: ${field.unique}`);
|
|
3461
3685
|
}
|
|
3686
|
+
if (field.type === "select") {
|
|
3687
|
+
const maxSelect = field.options?.maxSelect ?? 1;
|
|
3688
|
+
parts.push(` maxSelect: ${maxSelect}`);
|
|
3689
|
+
const values = field.options?.values ?? [];
|
|
3690
|
+
parts.push(` values: ${formatValue(values)}`);
|
|
3691
|
+
}
|
|
3462
3692
|
if (field.options && Object.keys(field.options).length > 0) {
|
|
3463
3693
|
for (const [key, value] of Object.entries(field.options)) {
|
|
3464
|
-
|
|
3694
|
+
if (field.type === "select" && (key === "maxSelect" || key === "values")) {
|
|
3695
|
+
continue;
|
|
3696
|
+
}
|
|
3697
|
+
if (field.type === "number" && key === "noDecimal") {
|
|
3698
|
+
parts.push(` onlyInt: ${formatValue(value)}`);
|
|
3699
|
+
} else {
|
|
3700
|
+
parts.push(` ${key}: ${formatValue(value)}`);
|
|
3701
|
+
}
|
|
3465
3702
|
}
|
|
3466
3703
|
}
|
|
3467
3704
|
if (field.relation && field.type === "relation") {
|
|
3468
3705
|
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
}
|
|
3477
|
-
if (field.relation.cascadeDelete !== void 0) {
|
|
3478
|
-
parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
|
|
3706
|
+
let collectionIdValue;
|
|
3707
|
+
if (isUsersCollection) {
|
|
3708
|
+
collectionIdValue = '"_pb_users_auth_"';
|
|
3709
|
+
} else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
|
|
3710
|
+
collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
|
|
3711
|
+
} else {
|
|
3712
|
+
collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
3479
3713
|
}
|
|
3714
|
+
parts.push(` collectionId: ${collectionIdValue}`);
|
|
3715
|
+
const maxSelect = field.relation.maxSelect ?? 1;
|
|
3716
|
+
parts.push(` maxSelect: ${maxSelect}`);
|
|
3717
|
+
const minSelect = field.relation.minSelect ?? null;
|
|
3718
|
+
parts.push(` minSelect: ${minSelect}`);
|
|
3719
|
+
const cascadeDelete = field.relation.cascadeDelete ?? false;
|
|
3720
|
+
parts.push(` cascadeDelete: ${cascadeDelete}`);
|
|
3480
3721
|
}
|
|
3481
3722
|
return parts.join(",\n");
|
|
3482
3723
|
}
|
|
3483
|
-
function generateFieldAddition(collectionName, field, varName, isLast = false) {
|
|
3724
|
+
function generateFieldAddition(collectionName, field, varName, isLast = false, collectionIdMap) {
|
|
3484
3725
|
const lines = [];
|
|
3485
3726
|
const constructorName = getFieldConstructorName(field.type);
|
|
3486
3727
|
const collectionVar = varName || `collection_${collectionName}_${field.name}`;
|
|
3487
3728
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3488
3729
|
lines.push(``);
|
|
3489
3730
|
lines.push(` ${collectionVar}.fields.add(new ${constructorName}({`);
|
|
3490
|
-
lines.push(generateFieldConstructorOptions(field));
|
|
3731
|
+
lines.push(generateFieldConstructorOptions(field, collectionIdMap));
|
|
3491
3732
|
lines.push(` }));`);
|
|
3492
3733
|
lines.push(``);
|
|
3493
3734
|
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
@@ -3537,7 +3778,7 @@ function generateIndexAddition(collectionName, index, varName, isLast = false) {
|
|
|
3537
3778
|
const lines = [];
|
|
3538
3779
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
3539
3780
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3540
|
-
lines.push(` ${collectionVar}.indexes.push(
|
|
3781
|
+
lines.push(` ${collectionVar}.indexes.push(${JSON.stringify(index)});`);
|
|
3541
3782
|
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
3542
3783
|
return lines.join("\n");
|
|
3543
3784
|
}
|
|
@@ -3546,7 +3787,7 @@ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
|
|
|
3546
3787
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
3547
3788
|
const indexVar = `${collectionVar}_indexToRemove`;
|
|
3548
3789
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
3549
|
-
lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx ===
|
|
3790
|
+
lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx === ${JSON.stringify(index)});`);
|
|
3550
3791
|
lines.push(` if (${indexVar} !== -1) {`);
|
|
3551
3792
|
lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
|
|
3552
3793
|
lines.push(` }`);
|
|
@@ -3575,16 +3816,213 @@ function generateCollectionDeletion(collectionName, varName = "collection", isLa
|
|
|
3575
3816
|
lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
|
|
3576
3817
|
return lines.join("\n");
|
|
3577
3818
|
}
|
|
3819
|
+
function generateOperationUpMigration(operation, collectionIdMap) {
|
|
3820
|
+
const lines = [];
|
|
3821
|
+
if (operation.type === "create") {
|
|
3822
|
+
const collection = operation.collection;
|
|
3823
|
+
const varName = `collection_${collection.name}`;
|
|
3824
|
+
lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
|
|
3825
|
+
} else if (operation.type === "modify") {
|
|
3826
|
+
const modification = operation.modifications;
|
|
3827
|
+
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
|
|
3828
|
+
let operationCount = 0;
|
|
3829
|
+
const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
|
|
3830
|
+
for (const field of modification.fieldsToAdd) {
|
|
3831
|
+
operationCount++;
|
|
3832
|
+
const varName = `collection_${collectionName}_add_${field.name}`;
|
|
3833
|
+
const isLast = operationCount === totalOperations;
|
|
3834
|
+
lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
|
|
3835
|
+
if (!isLast) lines.push("");
|
|
3836
|
+
}
|
|
3837
|
+
for (const fieldMod of modification.fieldsToModify) {
|
|
3838
|
+
operationCount++;
|
|
3839
|
+
const varName = `collection_${collectionName}_modify_${fieldMod.fieldName}`;
|
|
3840
|
+
const isLast = operationCount === totalOperations;
|
|
3841
|
+
lines.push(generateFieldModification(collectionName, fieldMod, varName, isLast));
|
|
3842
|
+
if (!isLast) lines.push("");
|
|
3843
|
+
}
|
|
3844
|
+
for (const field of modification.fieldsToRemove) {
|
|
3845
|
+
operationCount++;
|
|
3846
|
+
const varName = `collection_${collectionName}_remove_${field.name}`;
|
|
3847
|
+
const isLast = operationCount === totalOperations;
|
|
3848
|
+
lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
|
|
3849
|
+
if (!isLast) lines.push("");
|
|
3850
|
+
}
|
|
3851
|
+
for (let i = 0; i < modification.indexesToAdd.length; i++) {
|
|
3852
|
+
operationCount++;
|
|
3853
|
+
const index = modification.indexesToAdd[i];
|
|
3854
|
+
const varName = `collection_${collectionName}_addidx_${i}`;
|
|
3855
|
+
const isLast = operationCount === totalOperations;
|
|
3856
|
+
lines.push(generateIndexAddition(collectionName, index, varName, isLast));
|
|
3857
|
+
if (!isLast) lines.push("");
|
|
3858
|
+
}
|
|
3859
|
+
for (let i = 0; i < modification.indexesToRemove.length; i++) {
|
|
3860
|
+
operationCount++;
|
|
3861
|
+
const index = modification.indexesToRemove[i];
|
|
3862
|
+
const varName = `collection_${collectionName}_rmidx_${i}`;
|
|
3863
|
+
const isLast = operationCount === totalOperations;
|
|
3864
|
+
lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
|
|
3865
|
+
if (!isLast) lines.push("");
|
|
3866
|
+
}
|
|
3867
|
+
if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
|
|
3868
|
+
for (const permission of modification.permissionsToUpdate) {
|
|
3869
|
+
operationCount++;
|
|
3870
|
+
const varName = `collection_${collectionName}_perm_${permission.ruleType}`;
|
|
3871
|
+
const isLast = operationCount === totalOperations;
|
|
3872
|
+
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, isLast));
|
|
3873
|
+
if (!isLast) lines.push("");
|
|
3874
|
+
}
|
|
3875
|
+
} else if (modification.rulesToUpdate.length > 0) {
|
|
3876
|
+
for (const rule of modification.rulesToUpdate) {
|
|
3877
|
+
operationCount++;
|
|
3878
|
+
const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
|
|
3879
|
+
const isLast = operationCount === totalOperations;
|
|
3880
|
+
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName, isLast));
|
|
3881
|
+
if (!isLast) lines.push("");
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
} else if (operation.type === "delete") {
|
|
3885
|
+
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection.name;
|
|
3886
|
+
const varName = `collection_${collectionName}`;
|
|
3887
|
+
lines.push(generateCollectionDeletion(collectionName, varName, true));
|
|
3888
|
+
}
|
|
3889
|
+
let code = lines.join("\n");
|
|
3890
|
+
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
3891
|
+
const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
|
|
3892
|
+
const saveMatches = [...code.matchAll(savePattern)];
|
|
3893
|
+
const deleteMatches = [...code.matchAll(deletePattern)];
|
|
3894
|
+
const allMatches = [
|
|
3895
|
+
...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
|
|
3896
|
+
...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
|
|
3897
|
+
].sort((a, b) => b.index - a.index);
|
|
3898
|
+
if (allMatches.length > 0) {
|
|
3899
|
+
const lastMatch = allMatches[0];
|
|
3900
|
+
if (lastMatch.type === "save") {
|
|
3901
|
+
code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.save(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
|
|
3902
|
+
} else {
|
|
3903
|
+
code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.delete(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
return code;
|
|
3907
|
+
}
|
|
3908
|
+
function generateOperationDownMigration(operation, collectionIdMap) {
|
|
3909
|
+
const lines = [];
|
|
3910
|
+
if (operation.type === "create") {
|
|
3911
|
+
const collection = operation.collection;
|
|
3912
|
+
const varName = `collection_${collection.name}`;
|
|
3913
|
+
lines.push(generateCollectionDeletion(collection.name, varName, true));
|
|
3914
|
+
} else if (operation.type === "modify") {
|
|
3915
|
+
const modification = operation.modifications;
|
|
3916
|
+
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
|
|
3917
|
+
let operationCount = 0;
|
|
3918
|
+
const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
|
|
3919
|
+
if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
|
|
3920
|
+
for (const permission of modification.permissionsToUpdate) {
|
|
3921
|
+
operationCount++;
|
|
3922
|
+
const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
|
|
3923
|
+
const isLast = operationCount === totalOperations;
|
|
3924
|
+
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, isLast));
|
|
3925
|
+
if (!isLast) lines.push("");
|
|
3926
|
+
}
|
|
3927
|
+
} else if (modification.rulesToUpdate.length > 0) {
|
|
3928
|
+
for (const rule of modification.rulesToUpdate) {
|
|
3929
|
+
operationCount++;
|
|
3930
|
+
const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
|
|
3931
|
+
const isLast = operationCount === totalOperations;
|
|
3932
|
+
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName, isLast));
|
|
3933
|
+
if (!isLast) lines.push("");
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
for (let i = 0; i < modification.indexesToRemove.length; i++) {
|
|
3937
|
+
operationCount++;
|
|
3938
|
+
const index = modification.indexesToRemove[i];
|
|
3939
|
+
const varName = `collection_${collectionName}_restore_idx_${i}`;
|
|
3940
|
+
const isLast = operationCount === totalOperations;
|
|
3941
|
+
lines.push(generateIndexAddition(collectionName, index, varName, isLast));
|
|
3942
|
+
if (!isLast) lines.push("");
|
|
3943
|
+
}
|
|
3944
|
+
for (let i = 0; i < modification.indexesToAdd.length; i++) {
|
|
3945
|
+
operationCount++;
|
|
3946
|
+
const index = modification.indexesToAdd[i];
|
|
3947
|
+
const varName = `collection_${collectionName}_revert_idx_${i}`;
|
|
3948
|
+
const isLast = operationCount === totalOperations;
|
|
3949
|
+
lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
|
|
3950
|
+
if (!isLast) lines.push("");
|
|
3951
|
+
}
|
|
3952
|
+
for (const field of modification.fieldsToRemove) {
|
|
3953
|
+
operationCount++;
|
|
3954
|
+
const varName = `collection_${collectionName}_restore_${field.name}`;
|
|
3955
|
+
const isLast = operationCount === totalOperations;
|
|
3956
|
+
lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
|
|
3957
|
+
if (!isLast) lines.push("");
|
|
3958
|
+
}
|
|
3959
|
+
for (const fieldMod of modification.fieldsToModify) {
|
|
3960
|
+
operationCount++;
|
|
3961
|
+
const reverseChanges = fieldMod.changes.map((change) => ({
|
|
3962
|
+
property: change.property,
|
|
3963
|
+
oldValue: change.newValue,
|
|
3964
|
+
newValue: change.oldValue
|
|
3965
|
+
}));
|
|
3966
|
+
const reverseMod = {
|
|
3967
|
+
fieldName: fieldMod.fieldName,
|
|
3968
|
+
currentDefinition: fieldMod.newDefinition,
|
|
3969
|
+
newDefinition: fieldMod.currentDefinition,
|
|
3970
|
+
changes: reverseChanges
|
|
3971
|
+
};
|
|
3972
|
+
const varName = `collection_${collectionName}_revert_${fieldMod.fieldName}`;
|
|
3973
|
+
const isLast = operationCount === totalOperations;
|
|
3974
|
+
lines.push(generateFieldModification(collectionName, reverseMod, varName, isLast));
|
|
3975
|
+
if (!isLast) lines.push("");
|
|
3976
|
+
}
|
|
3977
|
+
for (const field of modification.fieldsToAdd) {
|
|
3978
|
+
operationCount++;
|
|
3979
|
+
const varName = `collection_${collectionName}_revert_add_${field.name}`;
|
|
3980
|
+
const isLast = operationCount === totalOperations;
|
|
3981
|
+
lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
|
|
3982
|
+
if (!isLast) lines.push("");
|
|
3983
|
+
}
|
|
3984
|
+
} else if (operation.type === "delete") {
|
|
3985
|
+
const collection = operation.collection;
|
|
3986
|
+
if (typeof collection !== "string") {
|
|
3987
|
+
const varName = `collection_${collection.name}`;
|
|
3988
|
+
lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
let code = lines.join("\n");
|
|
3992
|
+
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
3993
|
+
const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
|
|
3994
|
+
const saveMatches = [...code.matchAll(savePattern)];
|
|
3995
|
+
const deleteMatches = [...code.matchAll(deletePattern)];
|
|
3996
|
+
const allMatches = [
|
|
3997
|
+
...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
|
|
3998
|
+
...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
|
|
3999
|
+
].sort((a, b) => b.index - a.index);
|
|
4000
|
+
if (allMatches.length > 0) {
|
|
4001
|
+
const lastMatch = allMatches[0];
|
|
4002
|
+
if (lastMatch.type === "save") {
|
|
4003
|
+
code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.save(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
|
|
4004
|
+
} else {
|
|
4005
|
+
code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.delete(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
return code;
|
|
4009
|
+
}
|
|
3578
4010
|
function generateUpMigration(diff) {
|
|
3579
4011
|
const lines = [];
|
|
3580
4012
|
lines.push(` // UP MIGRATION`);
|
|
3581
4013
|
lines.push(``);
|
|
4014
|
+
const collectionIdMap = /* @__PURE__ */ new Map();
|
|
4015
|
+
for (const collection of diff.collectionsToCreate) {
|
|
4016
|
+
if (collection.id) {
|
|
4017
|
+
collectionIdMap.set(collection.name, collection.id);
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
3582
4020
|
if (diff.collectionsToCreate.length > 0) {
|
|
3583
4021
|
lines.push(` // Create new collections`);
|
|
3584
4022
|
for (let i = 0; i < diff.collectionsToCreate.length; i++) {
|
|
3585
4023
|
const collection = diff.collectionsToCreate[i];
|
|
3586
4024
|
const varName = `collection_${collection.name}_create`;
|
|
3587
|
-
lines.push(generateCollectionCreation(collection, varName));
|
|
4025
|
+
lines.push(generateCollectionCreation(collection, varName, false, collectionIdMap));
|
|
3588
4026
|
lines.push(``);
|
|
3589
4027
|
}
|
|
3590
4028
|
}
|
|
@@ -3596,7 +4034,7 @@ function generateUpMigration(diff) {
|
|
|
3596
4034
|
lines.push(` // Add fields to ${collectionName}`);
|
|
3597
4035
|
for (const field of modification.fieldsToAdd) {
|
|
3598
4036
|
const varName = `collection_${collectionName}_add_${field.name}`;
|
|
3599
|
-
lines.push(generateFieldAddition(collectionName, field, varName));
|
|
4037
|
+
lines.push(generateFieldAddition(collectionName, field, varName, false, collectionIdMap));
|
|
3600
4038
|
lines.push(``);
|
|
3601
4039
|
}
|
|
3602
4040
|
}
|
|
@@ -3687,12 +4125,23 @@ function generateDownMigration(diff) {
|
|
|
3687
4125
|
const lines = [];
|
|
3688
4126
|
lines.push(` // DOWN MIGRATION (ROLLBACK)`);
|
|
3689
4127
|
lines.push(``);
|
|
4128
|
+
const collectionIdMap = /* @__PURE__ */ new Map();
|
|
4129
|
+
for (const collection of diff.collectionsToCreate) {
|
|
4130
|
+
if (collection.id) {
|
|
4131
|
+
collectionIdMap.set(collection.name, collection.id);
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
for (const collection of diff.collectionsToDelete) {
|
|
4135
|
+
if (collection.id) {
|
|
4136
|
+
collectionIdMap.set(collection.name, collection.id);
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
3690
4139
|
if (diff.collectionsToDelete.length > 0) {
|
|
3691
4140
|
lines.push(` // Recreate deleted collections`);
|
|
3692
4141
|
for (let i = 0; i < diff.collectionsToDelete.length; i++) {
|
|
3693
4142
|
const collection = diff.collectionsToDelete[i];
|
|
3694
4143
|
const varName = `collection_${collection.name}_recreate`;
|
|
3695
|
-
lines.push(generateCollectionCreation(collection, varName));
|
|
4144
|
+
lines.push(generateCollectionCreation(collection, varName, false, collectionIdMap));
|
|
3696
4145
|
lines.push(``);
|
|
3697
4146
|
}
|
|
3698
4147
|
}
|
|
@@ -3737,7 +4186,7 @@ function generateDownMigration(diff) {
|
|
|
3737
4186
|
lines.push(` // Restore fields to ${collectionName}`);
|
|
3738
4187
|
for (const field of modification.fieldsToRemove) {
|
|
3739
4188
|
const varName = `collection_${collectionName}_restore_${field.name}`;
|
|
3740
|
-
lines.push(generateFieldAddition(collectionName, field, varName));
|
|
4189
|
+
lines.push(generateFieldAddition(collectionName, field, varName, false, collectionIdMap));
|
|
3741
4190
|
lines.push(``);
|
|
3742
4191
|
}
|
|
3743
4192
|
}
|
|
@@ -3806,12 +4255,33 @@ function generate(diff, config) {
|
|
|
3806
4255
|
const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
|
|
3807
4256
|
try {
|
|
3808
4257
|
const migrationDir = resolveMigrationDir(normalizedConfig);
|
|
3809
|
-
const
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
const
|
|
3814
|
-
|
|
4258
|
+
const hasChanges2 = diff.collectionsToCreate.length > 0 || diff.collectionsToModify.length > 0 || diff.collectionsToDelete.length > 0;
|
|
4259
|
+
if (!hasChanges2) {
|
|
4260
|
+
return [];
|
|
4261
|
+
}
|
|
4262
|
+
const collectionIdMap = /* @__PURE__ */ new Map();
|
|
4263
|
+
for (const collection of diff.collectionsToCreate) {
|
|
4264
|
+
if (collection.id) {
|
|
4265
|
+
collectionIdMap.set(collection.name, collection.id);
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
for (const collection of diff.collectionsToDelete) {
|
|
4269
|
+
if (collection.id) {
|
|
4270
|
+
collectionIdMap.set(collection.name, collection.id);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
const baseTimestamp = generateTimestamp(normalizedConfig);
|
|
4274
|
+
const operations = splitDiffByCollection(diff, baseTimestamp);
|
|
4275
|
+
const filePaths = [];
|
|
4276
|
+
for (const operation of operations) {
|
|
4277
|
+
const upCode = generateOperationUpMigration(operation, collectionIdMap);
|
|
4278
|
+
const downCode = generateOperationDownMigration(operation, collectionIdMap);
|
|
4279
|
+
const content = createMigrationFileStructure(upCode, downCode, normalizedConfig);
|
|
4280
|
+
const filename = generateCollectionMigrationFilename(operation);
|
|
4281
|
+
const filePath = writeMigrationFile(migrationDir, filename, content);
|
|
4282
|
+
filePaths.push(filePath);
|
|
4283
|
+
}
|
|
4284
|
+
return filePaths;
|
|
3815
4285
|
} catch (error) {
|
|
3816
4286
|
if (error instanceof MigrationGenerationError || error instanceof FileSystemError) {
|
|
3817
4287
|
throw error;
|
|
@@ -3829,7 +4299,8 @@ var MigrationGenerator = class {
|
|
|
3829
4299
|
this.config = mergeConfig4(config);
|
|
3830
4300
|
}
|
|
3831
4301
|
/**
|
|
3832
|
-
* Generates
|
|
4302
|
+
* Generates migration files from a schema diff
|
|
4303
|
+
* Returns array of file paths (one per collection operation)
|
|
3833
4304
|
*/
|
|
3834
4305
|
generate(diff) {
|
|
3835
4306
|
return generate(diff, this.config);
|