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/cli/migrate.js
CHANGED
|
@@ -7,6 +7,7 @@ import * as path5 from 'path';
|
|
|
7
7
|
import { dirname, join } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { z } from 'zod';
|
|
10
|
+
import { randomBytes } from 'crypto';
|
|
10
11
|
import ora from 'ora';
|
|
11
12
|
|
|
12
13
|
({
|
|
@@ -1292,12 +1293,22 @@ function isAuthCollection(fields) {
|
|
|
1292
1293
|
function buildFieldDefinition(fieldName, zodType) {
|
|
1293
1294
|
const fieldMetadata = extractFieldMetadata(zodType.description);
|
|
1294
1295
|
if (fieldMetadata) {
|
|
1295
|
-
|
|
1296
|
+
let required2;
|
|
1297
|
+
if (fieldMetadata.type === "number") {
|
|
1298
|
+
if (fieldMetadata.options?.required !== void 0) {
|
|
1299
|
+
required2 = fieldMetadata.options.required;
|
|
1300
|
+
} else {
|
|
1301
|
+
required2 = false;
|
|
1302
|
+
}
|
|
1303
|
+
} else {
|
|
1304
|
+
required2 = isFieldRequired(zodType);
|
|
1305
|
+
}
|
|
1306
|
+
const { required: _required, ...options2 } = fieldMetadata.options || {};
|
|
1296
1307
|
const fieldDef2 = {
|
|
1297
1308
|
name: fieldName,
|
|
1298
1309
|
type: fieldMetadata.type,
|
|
1299
1310
|
required: required2,
|
|
1300
|
-
options:
|
|
1311
|
+
options: Object.keys(options2).length > 0 ? options2 : void 0
|
|
1301
1312
|
};
|
|
1302
1313
|
if (fieldMetadata.type === "relation") {
|
|
1303
1314
|
const relationMetadata2 = extractRelationMetadata(zodType.description);
|
|
@@ -1467,6 +1478,67 @@ async function buildSchemaDefinition(config) {
|
|
|
1467
1478
|
async function parseSchemaFiles(config) {
|
|
1468
1479
|
return buildSchemaDefinition(config);
|
|
1469
1480
|
}
|
|
1481
|
+
function generateCollectionId() {
|
|
1482
|
+
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
1483
|
+
const idLength = 15;
|
|
1484
|
+
const bytes = randomBytes(idLength);
|
|
1485
|
+
let id = "pb_";
|
|
1486
|
+
for (let i = 0; i < idLength; i++) {
|
|
1487
|
+
const index = bytes[i] % chars.length;
|
|
1488
|
+
id += chars[index];
|
|
1489
|
+
}
|
|
1490
|
+
return id;
|
|
1491
|
+
}
|
|
1492
|
+
var CollectionIdRegistry = class {
|
|
1493
|
+
ids;
|
|
1494
|
+
constructor() {
|
|
1495
|
+
this.ids = /* @__PURE__ */ new Set();
|
|
1496
|
+
}
|
|
1497
|
+
/**
|
|
1498
|
+
* Generates a unique collection ID for a given collection name
|
|
1499
|
+
* Retries up to 10 times if collision occurs (extremely rare)
|
|
1500
|
+
* Special case: returns "_pb_users_auth_" for users collection
|
|
1501
|
+
*
|
|
1502
|
+
* @param collectionName - The name of the collection (optional)
|
|
1503
|
+
* @returns A unique collection ID
|
|
1504
|
+
* @throws Error if unable to generate unique ID after max attempts
|
|
1505
|
+
*/
|
|
1506
|
+
generate(collectionName) {
|
|
1507
|
+
if (collectionName && collectionName.toLowerCase() === "users") {
|
|
1508
|
+
const usersId = "_pb_users_auth_";
|
|
1509
|
+
if (!this.has(usersId)) {
|
|
1510
|
+
this.register(usersId);
|
|
1511
|
+
}
|
|
1512
|
+
return usersId;
|
|
1513
|
+
}
|
|
1514
|
+
const maxAttempts = 10;
|
|
1515
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
1516
|
+
const id = generateCollectionId();
|
|
1517
|
+
if (!this.has(id)) {
|
|
1518
|
+
this.register(id);
|
|
1519
|
+
return id;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
throw new Error("Failed to generate unique collection ID after maximum attempts");
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Checks if an ID has already been registered
|
|
1526
|
+
*
|
|
1527
|
+
* @param id - The collection ID to check
|
|
1528
|
+
* @returns True if the ID exists in the registry
|
|
1529
|
+
*/
|
|
1530
|
+
has(id) {
|
|
1531
|
+
return this.ids.has(id);
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Registers a collection ID in the registry
|
|
1535
|
+
*
|
|
1536
|
+
* @param id - The collection ID to register
|
|
1537
|
+
*/
|
|
1538
|
+
register(id) {
|
|
1539
|
+
this.ids.add(id);
|
|
1540
|
+
}
|
|
1541
|
+
};
|
|
1470
1542
|
|
|
1471
1543
|
// src/migration/diff.ts
|
|
1472
1544
|
var DEFAULT_CONFIG2 = {
|
|
@@ -1609,18 +1681,49 @@ function compareFieldConstraints(currentField, previousField) {
|
|
|
1609
1681
|
}
|
|
1610
1682
|
return changes;
|
|
1611
1683
|
}
|
|
1684
|
+
function normalizeOptionValue(key, value, fieldType) {
|
|
1685
|
+
if (key === "maxSelect" && value === 1 && (fieldType === "select" || fieldType === "file")) {
|
|
1686
|
+
return void 0;
|
|
1687
|
+
}
|
|
1688
|
+
if (key === "maxSize" && value === 0 && fieldType === "file") {
|
|
1689
|
+
return void 0;
|
|
1690
|
+
}
|
|
1691
|
+
if (fieldType === "file") {
|
|
1692
|
+
if (key === "mimeTypes" && Array.isArray(value) && value.length === 0) {
|
|
1693
|
+
return void 0;
|
|
1694
|
+
}
|
|
1695
|
+
if (key === "thumbs" && Array.isArray(value) && value.length === 0) {
|
|
1696
|
+
return void 0;
|
|
1697
|
+
}
|
|
1698
|
+
if (key === "protected" && value === false) {
|
|
1699
|
+
return void 0;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
if (fieldType === "autodate") {
|
|
1703
|
+
if (key === "onCreate" && value === true) {
|
|
1704
|
+
return void 0;
|
|
1705
|
+
}
|
|
1706
|
+
if (key === "onUpdate" && value === false) {
|
|
1707
|
+
return void 0;
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return value;
|
|
1711
|
+
}
|
|
1612
1712
|
function compareFieldOptions(currentField, previousField) {
|
|
1613
1713
|
const changes = [];
|
|
1614
1714
|
const currentOptions = currentField.options || {};
|
|
1615
1715
|
const previousOptions = previousField.options || {};
|
|
1616
1716
|
const allKeys = /* @__PURE__ */ new Set([...Object.keys(currentOptions), ...Object.keys(previousOptions)]);
|
|
1717
|
+
const fieldType = currentField.type;
|
|
1617
1718
|
for (const key of allKeys) {
|
|
1618
1719
|
const currentValue = currentOptions[key];
|
|
1619
1720
|
const previousValue = previousOptions[key];
|
|
1620
|
-
|
|
1721
|
+
const normalizedCurrent = normalizeOptionValue(key, currentValue, fieldType);
|
|
1722
|
+
const normalizedPrevious = normalizeOptionValue(key, previousValue, fieldType);
|
|
1723
|
+
if (normalizedCurrent === void 0 && normalizedPrevious === void 0) {
|
|
1621
1724
|
continue;
|
|
1622
1725
|
}
|
|
1623
|
-
if (!areValuesEqual(
|
|
1726
|
+
if (!areValuesEqual(normalizedCurrent, normalizedPrevious)) {
|
|
1624
1727
|
changes.push({
|
|
1625
1728
|
property: `options.${key}`,
|
|
1626
1729
|
oldValue: previousValue,
|
|
@@ -1630,7 +1733,7 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
1630
1733
|
}
|
|
1631
1734
|
return changes;
|
|
1632
1735
|
}
|
|
1633
|
-
function compareRelationConfigurations(currentField, previousField) {
|
|
1736
|
+
function compareRelationConfigurations(currentField, previousField, collectionIdToName) {
|
|
1634
1737
|
const changes = [];
|
|
1635
1738
|
const currentRelation = currentField.relation;
|
|
1636
1739
|
const previousRelation = previousField.relation;
|
|
@@ -1642,8 +1745,8 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1642
1745
|
}
|
|
1643
1746
|
const normalizeCollection = (collection) => {
|
|
1644
1747
|
if (!collection) return collection;
|
|
1645
|
-
if (
|
|
1646
|
-
return
|
|
1748
|
+
if (collectionIdToName && collectionIdToName.has(collection)) {
|
|
1749
|
+
return collectionIdToName.get(collection);
|
|
1647
1750
|
}
|
|
1648
1751
|
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
1649
1752
|
if (nameMatch) {
|
|
@@ -1653,13 +1756,11 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1653
1756
|
};
|
|
1654
1757
|
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
1655
1758
|
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
1656
|
-
if (normalizedCurrent !== normalizedPrevious) {
|
|
1759
|
+
if (normalizedCurrent.toLowerCase() !== normalizedPrevious.toLowerCase()) {
|
|
1657
1760
|
changes.push({
|
|
1658
1761
|
property: "relation.collection",
|
|
1659
|
-
oldValue:
|
|
1660
|
-
|
|
1661
|
-
newValue: normalizedCurrent
|
|
1662
|
-
// Use normalized value for clarity
|
|
1762
|
+
oldValue: previousRelation.collection,
|
|
1763
|
+
newValue: currentRelation.collection
|
|
1663
1764
|
});
|
|
1664
1765
|
}
|
|
1665
1766
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -1669,14 +1770,20 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1669
1770
|
newValue: currentRelation.cascadeDelete
|
|
1670
1771
|
});
|
|
1671
1772
|
}
|
|
1672
|
-
|
|
1773
|
+
const normalizeMax = (val) => val === 1 ? null : val;
|
|
1774
|
+
const currentMax = normalizeMax(currentRelation.maxSelect);
|
|
1775
|
+
const previousMax = normalizeMax(previousRelation.maxSelect);
|
|
1776
|
+
if (currentMax != previousMax) {
|
|
1673
1777
|
changes.push({
|
|
1674
1778
|
property: "relation.maxSelect",
|
|
1675
1779
|
oldValue: previousRelation.maxSelect,
|
|
1676
1780
|
newValue: currentRelation.maxSelect
|
|
1677
1781
|
});
|
|
1678
1782
|
}
|
|
1679
|
-
|
|
1783
|
+
const normalizeMin = (val) => val === 0 ? null : val;
|
|
1784
|
+
const currentMin = normalizeMin(currentRelation.minSelect);
|
|
1785
|
+
const previousMin = normalizeMin(previousRelation.minSelect);
|
|
1786
|
+
if (currentMin != previousMin) {
|
|
1680
1787
|
changes.push({
|
|
1681
1788
|
property: "relation.minSelect",
|
|
1682
1789
|
oldValue: previousRelation.minSelect,
|
|
@@ -1685,7 +1792,7 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1685
1792
|
}
|
|
1686
1793
|
return changes;
|
|
1687
1794
|
}
|
|
1688
|
-
function detectFieldChanges(currentField, previousField) {
|
|
1795
|
+
function detectFieldChanges(currentField, previousField, collectionIdToName) {
|
|
1689
1796
|
const changes = [];
|
|
1690
1797
|
const typeChange = compareFieldTypes(currentField, previousField);
|
|
1691
1798
|
if (typeChange) {
|
|
@@ -1694,7 +1801,7 @@ function detectFieldChanges(currentField, previousField) {
|
|
|
1694
1801
|
changes.push(...compareFieldConstraints(currentField, previousField));
|
|
1695
1802
|
changes.push(...compareFieldOptions(currentField, previousField));
|
|
1696
1803
|
if (currentField.type === "relation" && previousField.type === "relation") {
|
|
1697
|
-
changes.push(...compareRelationConfigurations(currentField, previousField));
|
|
1804
|
+
changes.push(...compareRelationConfigurations(currentField, previousField, collectionIdToName));
|
|
1698
1805
|
}
|
|
1699
1806
|
return changes;
|
|
1700
1807
|
}
|
|
@@ -1705,7 +1812,7 @@ function compareIndexes(currentIndexes = [], previousIndexes = []) {
|
|
|
1705
1812
|
const indexesToRemove = previousIndexes.filter((idx) => !currentSet.has(idx));
|
|
1706
1813
|
return { indexesToAdd, indexesToRemove };
|
|
1707
1814
|
}
|
|
1708
|
-
function compareRules(currentRules, previousRules) {
|
|
1815
|
+
function compareRules(currentRules, previousRules, currentPermissions, previousPermissions) {
|
|
1709
1816
|
const updates = [];
|
|
1710
1817
|
const ruleTypes = [
|
|
1711
1818
|
"listRule",
|
|
@@ -1716,8 +1823,8 @@ function compareRules(currentRules, previousRules) {
|
|
|
1716
1823
|
"manageRule"
|
|
1717
1824
|
];
|
|
1718
1825
|
for (const ruleType of ruleTypes) {
|
|
1719
|
-
const currentValue = currentRules?.[ruleType] ?? null;
|
|
1720
|
-
const previousValue = previousRules?.[ruleType] ?? null;
|
|
1826
|
+
const currentValue = currentRules?.[ruleType] ?? currentPermissions?.[ruleType] ?? null;
|
|
1827
|
+
const previousValue = previousRules?.[ruleType] ?? previousPermissions?.[ruleType] ?? null;
|
|
1721
1828
|
if (currentValue !== previousValue) {
|
|
1722
1829
|
updates.push({
|
|
1723
1830
|
ruleType,
|
|
@@ -1744,7 +1851,7 @@ function comparePermissions(currentPermissions, previousPermissions) {
|
|
|
1744
1851
|
}
|
|
1745
1852
|
return changes;
|
|
1746
1853
|
}
|
|
1747
|
-
function compareCollectionFields(currentCollection, previousCollection, config) {
|
|
1854
|
+
function compareCollectionFields(currentCollection, previousCollection, config, collectionIdToName) {
|
|
1748
1855
|
let fieldsToAdd = findNewFields(currentCollection.fields, previousCollection.fields);
|
|
1749
1856
|
const fieldsToRemove = findRemovedFields(currentCollection.fields, previousCollection.fields);
|
|
1750
1857
|
const fieldsToModify = [];
|
|
@@ -1754,7 +1861,7 @@ function compareCollectionFields(currentCollection, previousCollection, config)
|
|
|
1754
1861
|
}
|
|
1755
1862
|
const matchedFields = matchFieldsByName(currentCollection.fields, previousCollection.fields);
|
|
1756
1863
|
for (const [currentField, previousField] of matchedFields) {
|
|
1757
|
-
const changes = detectFieldChanges(currentField, previousField);
|
|
1864
|
+
const changes = detectFieldChanges(currentField, previousField, collectionIdToName);
|
|
1758
1865
|
if (changes.length > 0) {
|
|
1759
1866
|
fieldsToModify.push({
|
|
1760
1867
|
fieldName: currentField.name,
|
|
@@ -1766,14 +1873,20 @@ function compareCollectionFields(currentCollection, previousCollection, config)
|
|
|
1766
1873
|
}
|
|
1767
1874
|
return { fieldsToAdd, fieldsToRemove, fieldsToModify };
|
|
1768
1875
|
}
|
|
1769
|
-
function buildCollectionModification(currentCollection, previousCollection, config) {
|
|
1876
|
+
function buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName) {
|
|
1770
1877
|
const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(
|
|
1771
1878
|
currentCollection,
|
|
1772
1879
|
previousCollection,
|
|
1773
|
-
config
|
|
1880
|
+
config,
|
|
1881
|
+
collectionIdToName
|
|
1774
1882
|
);
|
|
1775
1883
|
const { indexesToAdd, indexesToRemove } = compareIndexes(currentCollection.indexes, previousCollection.indexes);
|
|
1776
|
-
const rulesToUpdate = compareRules(
|
|
1884
|
+
const rulesToUpdate = compareRules(
|
|
1885
|
+
currentCollection.rules,
|
|
1886
|
+
previousCollection.rules,
|
|
1887
|
+
currentCollection.permissions,
|
|
1888
|
+
previousCollection.permissions
|
|
1889
|
+
);
|
|
1777
1890
|
const permissionsToUpdate = comparePermissions(currentCollection.permissions, previousCollection.permissions);
|
|
1778
1891
|
return {
|
|
1779
1892
|
collection: currentCollection.name,
|
|
@@ -1790,6 +1903,14 @@ function hasChanges(modification) {
|
|
|
1790
1903
|
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;
|
|
1791
1904
|
}
|
|
1792
1905
|
function aggregateChanges(currentSchema, previousSnapshot, config) {
|
|
1906
|
+
const collectionIdToName = /* @__PURE__ */ new Map();
|
|
1907
|
+
if (previousSnapshot) {
|
|
1908
|
+
for (const [name, collection] of previousSnapshot.collections) {
|
|
1909
|
+
if (collection.id) {
|
|
1910
|
+
collectionIdToName.set(collection.id, name);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1793
1914
|
const collectionsToCreate = findNewCollections(currentSchema, previousSnapshot);
|
|
1794
1915
|
const collectionsToDelete = findRemovedCollections(currentSchema, previousSnapshot);
|
|
1795
1916
|
const filteredCollectionsToCreate = collectionsToCreate.filter(
|
|
@@ -1798,16 +1919,28 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
|
|
|
1798
1919
|
const filteredCollectionsToDelete = collectionsToDelete.filter(
|
|
1799
1920
|
(collection) => !isSystemCollection(collection.name, config)
|
|
1800
1921
|
);
|
|
1922
|
+
const registry = new CollectionIdRegistry();
|
|
1923
|
+
const collectionsWithIds = filteredCollectionsToCreate.map((collection) => {
|
|
1924
|
+
if (collection.id) {
|
|
1925
|
+
registry.register(collection.id);
|
|
1926
|
+
return collection;
|
|
1927
|
+
}
|
|
1928
|
+
const id = registry.generate(collection.name);
|
|
1929
|
+
return {
|
|
1930
|
+
...collection,
|
|
1931
|
+
id
|
|
1932
|
+
};
|
|
1933
|
+
});
|
|
1801
1934
|
const collectionsToModify = [];
|
|
1802
1935
|
const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);
|
|
1803
1936
|
for (const [currentCollection, previousCollection] of matchedCollections) {
|
|
1804
|
-
const modification = buildCollectionModification(currentCollection, previousCollection, config);
|
|
1937
|
+
const modification = buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName);
|
|
1805
1938
|
if (hasChanges(modification)) {
|
|
1806
1939
|
collectionsToModify.push(modification);
|
|
1807
1940
|
}
|
|
1808
1941
|
}
|
|
1809
1942
|
return {
|
|
1810
|
-
collectionsToCreate:
|
|
1943
|
+
collectionsToCreate: collectionsWithIds,
|
|
1811
1944
|
collectionsToDelete: filteredCollectionsToDelete,
|
|
1812
1945
|
collectionsToModify
|
|
1813
1946
|
};
|
|
@@ -1890,42 +2023,48 @@ function generateTimestamp(config) {
|
|
|
1890
2023
|
}
|
|
1891
2024
|
return Math.floor(Date.now() / 1e3).toString();
|
|
1892
2025
|
}
|
|
1893
|
-
function
|
|
1894
|
-
const
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
if (diff.collectionsToDelete.length === 1) {
|
|
1904
|
-
parts.push(`deleted_${diff.collectionsToDelete[0].name}`);
|
|
1905
|
-
} else {
|
|
1906
|
-
parts.push(`deleted_${diff.collectionsToDelete.length}_collections`);
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
|
-
if (diff.collectionsToModify.length > 0) {
|
|
1910
|
-
if (diff.collectionsToModify.length === 1) {
|
|
1911
|
-
parts.push(`updated_${diff.collectionsToModify[0].collection}`);
|
|
1912
|
-
} else {
|
|
1913
|
-
parts.push(`updated_${diff.collectionsToModify.length}_collections`);
|
|
1914
|
-
}
|
|
2026
|
+
function splitDiffByCollection(diff, baseTimestamp) {
|
|
2027
|
+
const operations = [];
|
|
2028
|
+
let currentTimestamp = parseInt(baseTimestamp, 10);
|
|
2029
|
+
for (const collection of diff.collectionsToCreate) {
|
|
2030
|
+
operations.push({
|
|
2031
|
+
type: "create",
|
|
2032
|
+
collection,
|
|
2033
|
+
timestamp: currentTimestamp.toString()
|
|
2034
|
+
});
|
|
2035
|
+
currentTimestamp += 1;
|
|
1915
2036
|
}
|
|
1916
|
-
|
|
1917
|
-
|
|
2037
|
+
for (const modification of diff.collectionsToModify) {
|
|
2038
|
+
operations.push({
|
|
2039
|
+
type: "modify",
|
|
2040
|
+
collection: modification.collection,
|
|
2041
|
+
modifications: modification,
|
|
2042
|
+
timestamp: currentTimestamp.toString()
|
|
2043
|
+
});
|
|
2044
|
+
currentTimestamp += 1;
|
|
1918
2045
|
}
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
2046
|
+
for (const collection of diff.collectionsToDelete) {
|
|
2047
|
+
operations.push({
|
|
2048
|
+
type: "delete",
|
|
2049
|
+
collection: collection.name || collection,
|
|
2050
|
+
// Handle both object and string
|
|
2051
|
+
timestamp: currentTimestamp.toString()
|
|
2052
|
+
});
|
|
2053
|
+
currentTimestamp += 1;
|
|
1922
2054
|
}
|
|
1923
|
-
return
|
|
2055
|
+
return operations;
|
|
1924
2056
|
}
|
|
1925
|
-
function
|
|
1926
|
-
const timestamp =
|
|
1927
|
-
const
|
|
1928
|
-
|
|
2057
|
+
function generateCollectionMigrationFilename(operation) {
|
|
2058
|
+
const timestamp = operation.timestamp;
|
|
2059
|
+
const operationType = operation.type === "modify" ? "updated" : operation.type === "create" ? "created" : "deleted";
|
|
2060
|
+
let collectionName;
|
|
2061
|
+
if (typeof operation.collection === "string") {
|
|
2062
|
+
collectionName = operation.collection;
|
|
2063
|
+
} else {
|
|
2064
|
+
collectionName = operation.collection.name;
|
|
2065
|
+
}
|
|
2066
|
+
const sanitizedName = collectionName.replace(/[^a-zA-Z0-9_]/g, "_").toLowerCase();
|
|
2067
|
+
return `${timestamp}_${operationType}_${sanitizedName}.js`;
|
|
1929
2068
|
}
|
|
1930
2069
|
function createMigrationFileStructure(upCode, downCode, config) {
|
|
1931
2070
|
const mergedConfig = config ? mergeConfig3(config) : DEFAULT_CONFIG3;
|
|
@@ -1997,14 +2136,13 @@ function formatValue(value) {
|
|
|
1997
2136
|
return "null";
|
|
1998
2137
|
}
|
|
1999
2138
|
if (typeof value === "string") {
|
|
2000
|
-
return
|
|
2139
|
+
return JSON.stringify(value);
|
|
2001
2140
|
}
|
|
2002
2141
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
2003
2142
|
return String(value);
|
|
2004
2143
|
}
|
|
2005
2144
|
if (Array.isArray(value)) {
|
|
2006
|
-
|
|
2007
|
-
return `[${items}]`;
|
|
2145
|
+
return JSON.stringify(value).replace(/","/g, '", "');
|
|
2008
2146
|
}
|
|
2009
2147
|
if (typeof value === "object") {
|
|
2010
2148
|
const entries = Object.entries(value).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
|
|
@@ -2012,7 +2150,7 @@ function formatValue(value) {
|
|
|
2012
2150
|
}
|
|
2013
2151
|
return String(value);
|
|
2014
2152
|
}
|
|
2015
|
-
function generateFieldDefinitionObject(field) {
|
|
2153
|
+
function generateFieldDefinitionObject(field, collectionIdMap) {
|
|
2016
2154
|
const parts = [];
|
|
2017
2155
|
parts.push(` name: "${field.name}"`);
|
|
2018
2156
|
parts.push(` type: "${field.type}"`);
|
|
@@ -2020,34 +2158,47 @@ function generateFieldDefinitionObject(field) {
|
|
|
2020
2158
|
if (field.unique !== void 0) {
|
|
2021
2159
|
parts.push(` unique: ${field.unique}`);
|
|
2022
2160
|
}
|
|
2161
|
+
if (field.type === "select") {
|
|
2162
|
+
const maxSelect = field.options?.maxSelect ?? 1;
|
|
2163
|
+
parts.push(` maxSelect: ${maxSelect}`);
|
|
2164
|
+
const values = field.options?.values ?? [];
|
|
2165
|
+
parts.push(` values: ${formatValue(values)}`);
|
|
2166
|
+
}
|
|
2023
2167
|
if (field.options && Object.keys(field.options).length > 0) {
|
|
2024
2168
|
for (const [key, value] of Object.entries(field.options)) {
|
|
2169
|
+
if (field.type === "select" && (key === "maxSelect" || key === "values")) {
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2025
2172
|
parts.push(` ${key}: ${formatValue(value)}`);
|
|
2026
2173
|
}
|
|
2027
2174
|
}
|
|
2028
2175
|
if (field.relation) {
|
|
2029
2176
|
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
}
|
|
2038
|
-
if (field.relation.cascadeDelete !== void 0) {
|
|
2039
|
-
parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
|
|
2177
|
+
let collectionIdValue;
|
|
2178
|
+
if (isUsersCollection) {
|
|
2179
|
+
collectionIdValue = '"_pb_users_auth_"';
|
|
2180
|
+
} else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
|
|
2181
|
+
collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
|
|
2182
|
+
} else {
|
|
2183
|
+
collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
2040
2184
|
}
|
|
2185
|
+
parts.push(` collectionId: ${collectionIdValue}`);
|
|
2186
|
+
const maxSelect = field.relation.maxSelect ?? 1;
|
|
2187
|
+
parts.push(` maxSelect: ${maxSelect}`);
|
|
2188
|
+
const minSelect = field.relation.minSelect ?? null;
|
|
2189
|
+
parts.push(` minSelect: ${minSelect}`);
|
|
2190
|
+
const cascadeDelete = field.relation.cascadeDelete ?? false;
|
|
2191
|
+
parts.push(` cascadeDelete: ${cascadeDelete}`);
|
|
2041
2192
|
}
|
|
2042
2193
|
return ` {
|
|
2043
2194
|
${parts.join(",\n")},
|
|
2044
2195
|
}`;
|
|
2045
2196
|
}
|
|
2046
|
-
function generateFieldsArray(fields) {
|
|
2197
|
+
function generateFieldsArray(fields, collectionIdMap) {
|
|
2047
2198
|
if (fields.length === 0) {
|
|
2048
2199
|
return "[]";
|
|
2049
2200
|
}
|
|
2050
|
-
const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field));
|
|
2201
|
+
const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field, collectionIdMap));
|
|
2051
2202
|
return `[
|
|
2052
2203
|
${fieldObjects.join(",\n")},
|
|
2053
2204
|
]`;
|
|
@@ -2106,7 +2257,7 @@ function generateIndexesArray(indexes) {
|
|
|
2106
2257
|
if (!indexes || indexes.length === 0) {
|
|
2107
2258
|
return "[]";
|
|
2108
2259
|
}
|
|
2109
|
-
const indexStrings = indexes.map((idx) =>
|
|
2260
|
+
const indexStrings = indexes.map((idx) => JSON.stringify(idx));
|
|
2110
2261
|
return `[
|
|
2111
2262
|
${indexStrings.join(",\n ")},
|
|
2112
2263
|
]`;
|
|
@@ -2160,9 +2311,12 @@ function getSystemFields() {
|
|
|
2160
2311
|
}
|
|
2161
2312
|
];
|
|
2162
2313
|
}
|
|
2163
|
-
function generateCollectionCreation(collection, varName = "collection", isLast = false) {
|
|
2314
|
+
function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
|
|
2164
2315
|
const lines = [];
|
|
2165
2316
|
lines.push(` const ${varName} = new Collection({`);
|
|
2317
|
+
if (collection.id) {
|
|
2318
|
+
lines.push(` id: ${formatValue(collection.id)},`);
|
|
2319
|
+
}
|
|
2166
2320
|
lines.push(` name: "${collection.name}",`);
|
|
2167
2321
|
lines.push(` type: "${collection.type}",`);
|
|
2168
2322
|
const permissionsCode = generateCollectionPermissions(collection.permissions);
|
|
@@ -2174,7 +2328,7 @@ function generateCollectionCreation(collection, varName = "collection", isLast =
|
|
|
2174
2328
|
}
|
|
2175
2329
|
const systemFields = getSystemFields();
|
|
2176
2330
|
const allFields = [...systemFields, ...collection.fields];
|
|
2177
|
-
lines.push(` fields: ${generateFieldsArray(allFields)},`);
|
|
2331
|
+
lines.push(` fields: ${generateFieldsArray(allFields, collectionIdMap)},`);
|
|
2178
2332
|
lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
|
|
2179
2333
|
lines.push(` });`);
|
|
2180
2334
|
lines.push(``);
|
|
@@ -2196,42 +2350,59 @@ function getFieldConstructorName(fieldType) {
|
|
|
2196
2350
|
};
|
|
2197
2351
|
return constructorMap[fieldType] || "TextField";
|
|
2198
2352
|
}
|
|
2199
|
-
function generateFieldConstructorOptions(field) {
|
|
2353
|
+
function generateFieldConstructorOptions(field, collectionIdMap) {
|
|
2200
2354
|
const parts = [];
|
|
2201
2355
|
parts.push(` name: "${field.name}"`);
|
|
2202
2356
|
parts.push(` required: ${field.required}`);
|
|
2203
2357
|
if (field.unique !== void 0) {
|
|
2204
2358
|
parts.push(` unique: ${field.unique}`);
|
|
2205
2359
|
}
|
|
2360
|
+
if (field.type === "select") {
|
|
2361
|
+
const maxSelect = field.options?.maxSelect ?? 1;
|
|
2362
|
+
parts.push(` maxSelect: ${maxSelect}`);
|
|
2363
|
+
const values = field.options?.values ?? [];
|
|
2364
|
+
parts.push(` values: ${formatValue(values)}`);
|
|
2365
|
+
}
|
|
2206
2366
|
if (field.options && Object.keys(field.options).length > 0) {
|
|
2207
2367
|
for (const [key, value] of Object.entries(field.options)) {
|
|
2208
|
-
|
|
2368
|
+
if (field.type === "select" && (key === "maxSelect" || key === "values")) {
|
|
2369
|
+
continue;
|
|
2370
|
+
}
|
|
2371
|
+
if (field.type === "number" && key === "noDecimal") {
|
|
2372
|
+
parts.push(` onlyInt: ${formatValue(value)}`);
|
|
2373
|
+
} else {
|
|
2374
|
+
parts.push(` ${key}: ${formatValue(value)}`);
|
|
2375
|
+
}
|
|
2209
2376
|
}
|
|
2210
2377
|
}
|
|
2211
2378
|
if (field.relation && field.type === "relation") {
|
|
2212
2379
|
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
}
|
|
2221
|
-
if (field.relation.cascadeDelete !== void 0) {
|
|
2222
|
-
parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
|
|
2380
|
+
let collectionIdValue;
|
|
2381
|
+
if (isUsersCollection) {
|
|
2382
|
+
collectionIdValue = '"_pb_users_auth_"';
|
|
2383
|
+
} else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
|
|
2384
|
+
collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
|
|
2385
|
+
} else {
|
|
2386
|
+
collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
2223
2387
|
}
|
|
2388
|
+
parts.push(` collectionId: ${collectionIdValue}`);
|
|
2389
|
+
const maxSelect = field.relation.maxSelect ?? 1;
|
|
2390
|
+
parts.push(` maxSelect: ${maxSelect}`);
|
|
2391
|
+
const minSelect = field.relation.minSelect ?? null;
|
|
2392
|
+
parts.push(` minSelect: ${minSelect}`);
|
|
2393
|
+
const cascadeDelete = field.relation.cascadeDelete ?? false;
|
|
2394
|
+
parts.push(` cascadeDelete: ${cascadeDelete}`);
|
|
2224
2395
|
}
|
|
2225
2396
|
return parts.join(",\n");
|
|
2226
2397
|
}
|
|
2227
|
-
function generateFieldAddition(collectionName, field, varName, isLast = false) {
|
|
2398
|
+
function generateFieldAddition(collectionName, field, varName, isLast = false, collectionIdMap) {
|
|
2228
2399
|
const lines = [];
|
|
2229
2400
|
const constructorName = getFieldConstructorName(field.type);
|
|
2230
2401
|
const collectionVar = varName || `collection_${collectionName}_${field.name}`;
|
|
2231
2402
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
2232
2403
|
lines.push(``);
|
|
2233
2404
|
lines.push(` ${collectionVar}.fields.add(new ${constructorName}({`);
|
|
2234
|
-
lines.push(generateFieldConstructorOptions(field));
|
|
2405
|
+
lines.push(generateFieldConstructorOptions(field, collectionIdMap));
|
|
2235
2406
|
lines.push(` }));`);
|
|
2236
2407
|
lines.push(``);
|
|
2237
2408
|
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
@@ -2281,7 +2452,7 @@ function generateIndexAddition(collectionName, index, varName, isLast = false) {
|
|
|
2281
2452
|
const lines = [];
|
|
2282
2453
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
2283
2454
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
2284
|
-
lines.push(` ${collectionVar}.indexes.push(
|
|
2455
|
+
lines.push(` ${collectionVar}.indexes.push(${JSON.stringify(index)});`);
|
|
2285
2456
|
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
2286
2457
|
return lines.join("\n");
|
|
2287
2458
|
}
|
|
@@ -2290,7 +2461,7 @@ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
|
|
|
2290
2461
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
2291
2462
|
const indexVar = `${collectionVar}_indexToRemove`;
|
|
2292
2463
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
2293
|
-
lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx ===
|
|
2464
|
+
lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx === ${JSON.stringify(index)});`);
|
|
2294
2465
|
lines.push(` if (${indexVar} !== -1) {`);
|
|
2295
2466
|
lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
|
|
2296
2467
|
lines.push(` }`);
|
|
@@ -2319,94 +2490,75 @@ function generateCollectionDeletion(collectionName, varName = "collection", isLa
|
|
|
2319
2490
|
lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
|
|
2320
2491
|
return lines.join("\n");
|
|
2321
2492
|
}
|
|
2322
|
-
function
|
|
2493
|
+
function generateOperationUpMigration(operation, collectionIdMap) {
|
|
2323
2494
|
const lines = [];
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
lines.push(
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2495
|
+
if (operation.type === "create") {
|
|
2496
|
+
const collection = operation.collection;
|
|
2497
|
+
const varName = `collection_${collection.name}`;
|
|
2498
|
+
lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
|
|
2499
|
+
} else if (operation.type === "modify") {
|
|
2500
|
+
const modification = operation.modifications;
|
|
2501
|
+
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
|
|
2502
|
+
let operationCount = 0;
|
|
2503
|
+
const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
|
|
2504
|
+
for (const field of modification.fieldsToAdd) {
|
|
2505
|
+
operationCount++;
|
|
2506
|
+
const varName = `collection_${collectionName}_add_${field.name}`;
|
|
2507
|
+
const isLast = operationCount === totalOperations;
|
|
2508
|
+
lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
|
|
2509
|
+
if (!isLast) lines.push("");
|
|
2333
2510
|
}
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
if (
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
}
|
|
2372
|
-
if (modification.indexesToRemove.length > 0) {
|
|
2373
|
-
lines.push(` // Remove indexes from ${collectionName}`);
|
|
2374
|
-
for (let i = 0; i < modification.indexesToRemove.length; i++) {
|
|
2375
|
-
const index = modification.indexesToRemove[i];
|
|
2376
|
-
const varName = `collection_${collectionName}_rmidx_${i}`;
|
|
2377
|
-
lines.push(generateIndexRemoval(collectionName, index, varName));
|
|
2378
|
-
lines.push(``);
|
|
2379
|
-
}
|
|
2511
|
+
for (const fieldMod of modification.fieldsToModify) {
|
|
2512
|
+
operationCount++;
|
|
2513
|
+
const varName = `collection_${collectionName}_modify_${fieldMod.fieldName}`;
|
|
2514
|
+
const isLast = operationCount === totalOperations;
|
|
2515
|
+
lines.push(generateFieldModification(collectionName, fieldMod, varName, isLast));
|
|
2516
|
+
if (!isLast) lines.push("");
|
|
2517
|
+
}
|
|
2518
|
+
for (const field of modification.fieldsToRemove) {
|
|
2519
|
+
operationCount++;
|
|
2520
|
+
const varName = `collection_${collectionName}_remove_${field.name}`;
|
|
2521
|
+
const isLast = operationCount === totalOperations;
|
|
2522
|
+
lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
|
|
2523
|
+
if (!isLast) lines.push("");
|
|
2524
|
+
}
|
|
2525
|
+
for (let i = 0; i < modification.indexesToAdd.length; i++) {
|
|
2526
|
+
operationCount++;
|
|
2527
|
+
const index = modification.indexesToAdd[i];
|
|
2528
|
+
const varName = `collection_${collectionName}_addidx_${i}`;
|
|
2529
|
+
const isLast = operationCount === totalOperations;
|
|
2530
|
+
lines.push(generateIndexAddition(collectionName, index, varName, isLast));
|
|
2531
|
+
if (!isLast) lines.push("");
|
|
2532
|
+
}
|
|
2533
|
+
for (let i = 0; i < modification.indexesToRemove.length; i++) {
|
|
2534
|
+
operationCount++;
|
|
2535
|
+
const index = modification.indexesToRemove[i];
|
|
2536
|
+
const varName = `collection_${collectionName}_rmidx_${i}`;
|
|
2537
|
+
const isLast = operationCount === totalOperations;
|
|
2538
|
+
lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
|
|
2539
|
+
if (!isLast) lines.push("");
|
|
2540
|
+
}
|
|
2541
|
+
if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
|
|
2542
|
+
for (const permission of modification.permissionsToUpdate) {
|
|
2543
|
+
operationCount++;
|
|
2544
|
+
const varName = `collection_${collectionName}_perm_${permission.ruleType}`;
|
|
2545
|
+
const isLast = operationCount === totalOperations;
|
|
2546
|
+
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, isLast));
|
|
2547
|
+
if (!isLast) lines.push("");
|
|
2380
2548
|
}
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
} else if (modification.rulesToUpdate.length > 0) {
|
|
2389
|
-
lines.push(` // Update rules for ${collectionName}`);
|
|
2390
|
-
for (const rule of modification.rulesToUpdate) {
|
|
2391
|
-
const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
|
|
2392
|
-
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName));
|
|
2393
|
-
lines.push(``);
|
|
2394
|
-
}
|
|
2549
|
+
} else if (modification.rulesToUpdate.length > 0) {
|
|
2550
|
+
for (const rule of modification.rulesToUpdate) {
|
|
2551
|
+
operationCount++;
|
|
2552
|
+
const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
|
|
2553
|
+
const isLast = operationCount === totalOperations;
|
|
2554
|
+
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName, isLast));
|
|
2555
|
+
if (!isLast) lines.push("");
|
|
2395
2556
|
}
|
|
2396
2557
|
}
|
|
2397
|
-
}
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
const collection = diff.collectionsToDelete[i];
|
|
2402
|
-
const varName = `collection_${collection.name}_delete`;
|
|
2403
|
-
lines.push(generateCollectionDeletion(collection.name, varName));
|
|
2404
|
-
lines.push(``);
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2407
|
-
if (lines.length === 2) {
|
|
2408
|
-
lines.push(` // No changes detected`);
|
|
2409
|
-
lines.push(``);
|
|
2558
|
+
} else if (operation.type === "delete") {
|
|
2559
|
+
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection.name;
|
|
2560
|
+
const varName = `collection_${collectionName}`;
|
|
2561
|
+
lines.push(generateCollectionDeletion(collectionName, varName, true));
|
|
2410
2562
|
}
|
|
2411
2563
|
let code = lines.join("\n");
|
|
2412
2564
|
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
@@ -2427,105 +2579,88 @@ function generateUpMigration(diff) {
|
|
|
2427
2579
|
}
|
|
2428
2580
|
return code;
|
|
2429
2581
|
}
|
|
2430
|
-
function
|
|
2582
|
+
function generateOperationDownMigration(operation, collectionIdMap) {
|
|
2431
2583
|
const lines = [];
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
lines.push(
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
lines.push(` // Revert permissions for ${collectionName}`);
|
|
2449
|
-
for (const permission of modification.permissionsToUpdate) {
|
|
2450
|
-
const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
|
|
2451
|
-
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName));
|
|
2452
|
-
lines.push(``);
|
|
2453
|
-
}
|
|
2454
|
-
} else if (modification.rulesToUpdate.length > 0) {
|
|
2455
|
-
lines.push(` // Revert rules for ${collectionName}`);
|
|
2456
|
-
for (const rule of modification.rulesToUpdate) {
|
|
2457
|
-
const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
|
|
2458
|
-
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName));
|
|
2459
|
-
lines.push(``);
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
if (modification.indexesToRemove.length > 0) {
|
|
2463
|
-
lines.push(` // Restore indexes to ${collectionName}`);
|
|
2464
|
-
for (let i = 0; i < modification.indexesToRemove.length; i++) {
|
|
2465
|
-
const index = modification.indexesToRemove[i];
|
|
2466
|
-
const varName = `collection_${collectionName}_restore_idx_${i}`;
|
|
2467
|
-
lines.push(generateIndexAddition(collectionName, index, varName));
|
|
2468
|
-
lines.push(``);
|
|
2469
|
-
}
|
|
2470
|
-
}
|
|
2471
|
-
if (modification.indexesToAdd.length > 0) {
|
|
2472
|
-
lines.push(` // Remove indexes from ${collectionName}`);
|
|
2473
|
-
for (let i = 0; i < modification.indexesToAdd.length; i++) {
|
|
2474
|
-
const index = modification.indexesToAdd[i];
|
|
2475
|
-
const varName = `collection_${collectionName}_revert_idx_${i}`;
|
|
2476
|
-
lines.push(generateIndexRemoval(collectionName, index, varName));
|
|
2477
|
-
lines.push(``);
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
if (modification.fieldsToRemove.length > 0) {
|
|
2481
|
-
lines.push(` // Restore fields to ${collectionName}`);
|
|
2482
|
-
for (const field of modification.fieldsToRemove) {
|
|
2483
|
-
const varName = `collection_${collectionName}_restore_${field.name}`;
|
|
2484
|
-
lines.push(generateFieldAddition(collectionName, field, varName));
|
|
2485
|
-
lines.push(``);
|
|
2486
|
-
}
|
|
2584
|
+
if (operation.type === "create") {
|
|
2585
|
+
const collection = operation.collection;
|
|
2586
|
+
const varName = `collection_${collection.name}`;
|
|
2587
|
+
lines.push(generateCollectionDeletion(collection.name, varName, true));
|
|
2588
|
+
} else if (operation.type === "modify") {
|
|
2589
|
+
const modification = operation.modifications;
|
|
2590
|
+
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
|
|
2591
|
+
let operationCount = 0;
|
|
2592
|
+
const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
|
|
2593
|
+
if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
|
|
2594
|
+
for (const permission of modification.permissionsToUpdate) {
|
|
2595
|
+
operationCount++;
|
|
2596
|
+
const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
|
|
2597
|
+
const isLast = operationCount === totalOperations;
|
|
2598
|
+
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, isLast));
|
|
2599
|
+
if (!isLast) lines.push("");
|
|
2487
2600
|
}
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
}));
|
|
2496
|
-
const reverseMod = {
|
|
2497
|
-
fieldName: fieldMod.fieldName,
|
|
2498
|
-
currentDefinition: fieldMod.newDefinition,
|
|
2499
|
-
newDefinition: fieldMod.currentDefinition,
|
|
2500
|
-
changes: reverseChanges
|
|
2501
|
-
};
|
|
2502
|
-
const varName = `collection_${collectionName}_revert_${fieldMod.fieldName}`;
|
|
2503
|
-
lines.push(generateFieldModification(collectionName, reverseMod, varName));
|
|
2504
|
-
lines.push(``);
|
|
2505
|
-
}
|
|
2506
|
-
}
|
|
2507
|
-
if (modification.fieldsToAdd.length > 0) {
|
|
2508
|
-
lines.push(` // Remove added fields from ${collectionName}`);
|
|
2509
|
-
for (const field of modification.fieldsToAdd) {
|
|
2510
|
-
const varName = `collection_${collectionName}_revert_add_${field.name}`;
|
|
2511
|
-
lines.push(generateFieldDeletion(collectionName, field.name, varName));
|
|
2512
|
-
lines.push(``);
|
|
2513
|
-
}
|
|
2601
|
+
} else if (modification.rulesToUpdate.length > 0) {
|
|
2602
|
+
for (const rule of modification.rulesToUpdate) {
|
|
2603
|
+
operationCount++;
|
|
2604
|
+
const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
|
|
2605
|
+
const isLast = operationCount === totalOperations;
|
|
2606
|
+
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName, isLast));
|
|
2607
|
+
if (!isLast) lines.push("");
|
|
2514
2608
|
}
|
|
2515
2609
|
}
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
const
|
|
2521
|
-
|
|
2522
|
-
lines.push(
|
|
2523
|
-
|
|
2610
|
+
for (let i = 0; i < modification.indexesToRemove.length; i++) {
|
|
2611
|
+
operationCount++;
|
|
2612
|
+
const index = modification.indexesToRemove[i];
|
|
2613
|
+
const varName = `collection_${collectionName}_restore_idx_${i}`;
|
|
2614
|
+
const isLast = operationCount === totalOperations;
|
|
2615
|
+
lines.push(generateIndexAddition(collectionName, index, varName, isLast));
|
|
2616
|
+
if (!isLast) lines.push("");
|
|
2617
|
+
}
|
|
2618
|
+
for (let i = 0; i < modification.indexesToAdd.length; i++) {
|
|
2619
|
+
operationCount++;
|
|
2620
|
+
const index = modification.indexesToAdd[i];
|
|
2621
|
+
const varName = `collection_${collectionName}_revert_idx_${i}`;
|
|
2622
|
+
const isLast = operationCount === totalOperations;
|
|
2623
|
+
lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
|
|
2624
|
+
if (!isLast) lines.push("");
|
|
2625
|
+
}
|
|
2626
|
+
for (const field of modification.fieldsToRemove) {
|
|
2627
|
+
operationCount++;
|
|
2628
|
+
const varName = `collection_${collectionName}_restore_${field.name}`;
|
|
2629
|
+
const isLast = operationCount === totalOperations;
|
|
2630
|
+
lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
|
|
2631
|
+
if (!isLast) lines.push("");
|
|
2632
|
+
}
|
|
2633
|
+
for (const fieldMod of modification.fieldsToModify) {
|
|
2634
|
+
operationCount++;
|
|
2635
|
+
const reverseChanges = fieldMod.changes.map((change) => ({
|
|
2636
|
+
property: change.property,
|
|
2637
|
+
oldValue: change.newValue,
|
|
2638
|
+
newValue: change.oldValue
|
|
2639
|
+
}));
|
|
2640
|
+
const reverseMod = {
|
|
2641
|
+
fieldName: fieldMod.fieldName,
|
|
2642
|
+
currentDefinition: fieldMod.newDefinition,
|
|
2643
|
+
newDefinition: fieldMod.currentDefinition,
|
|
2644
|
+
changes: reverseChanges
|
|
2645
|
+
};
|
|
2646
|
+
const varName = `collection_${collectionName}_revert_${fieldMod.fieldName}`;
|
|
2647
|
+
const isLast = operationCount === totalOperations;
|
|
2648
|
+
lines.push(generateFieldModification(collectionName, reverseMod, varName, isLast));
|
|
2649
|
+
if (!isLast) lines.push("");
|
|
2650
|
+
}
|
|
2651
|
+
for (const field of modification.fieldsToAdd) {
|
|
2652
|
+
operationCount++;
|
|
2653
|
+
const varName = `collection_${collectionName}_revert_add_${field.name}`;
|
|
2654
|
+
const isLast = operationCount === totalOperations;
|
|
2655
|
+
lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
|
|
2656
|
+
if (!isLast) lines.push("");
|
|
2657
|
+
}
|
|
2658
|
+
} else if (operation.type === "delete") {
|
|
2659
|
+
const collection = operation.collection;
|
|
2660
|
+
if (typeof collection !== "string") {
|
|
2661
|
+
const varName = `collection_${collection.name}`;
|
|
2662
|
+
lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
|
|
2524
2663
|
}
|
|
2525
|
-
}
|
|
2526
|
-
if (lines.length === 2) {
|
|
2527
|
-
lines.push(` // No changes to revert`);
|
|
2528
|
-
lines.push(``);
|
|
2529
2664
|
}
|
|
2530
2665
|
let code = lines.join("\n");
|
|
2531
2666
|
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
@@ -2550,12 +2685,33 @@ function generate(diff, config) {
|
|
|
2550
2685
|
const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
|
|
2551
2686
|
try {
|
|
2552
2687
|
const migrationDir = resolveMigrationDir(normalizedConfig);
|
|
2553
|
-
const
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
const
|
|
2558
|
-
|
|
2688
|
+
const hasChanges4 = diff.collectionsToCreate.length > 0 || diff.collectionsToModify.length > 0 || diff.collectionsToDelete.length > 0;
|
|
2689
|
+
if (!hasChanges4) {
|
|
2690
|
+
return [];
|
|
2691
|
+
}
|
|
2692
|
+
const collectionIdMap = /* @__PURE__ */ new Map();
|
|
2693
|
+
for (const collection of diff.collectionsToCreate) {
|
|
2694
|
+
if (collection.id) {
|
|
2695
|
+
collectionIdMap.set(collection.name, collection.id);
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
for (const collection of diff.collectionsToDelete) {
|
|
2699
|
+
if (collection.id) {
|
|
2700
|
+
collectionIdMap.set(collection.name, collection.id);
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
const baseTimestamp = generateTimestamp(normalizedConfig);
|
|
2704
|
+
const operations = splitDiffByCollection(diff, baseTimestamp);
|
|
2705
|
+
const filePaths = [];
|
|
2706
|
+
for (const operation of operations) {
|
|
2707
|
+
const upCode = generateOperationUpMigration(operation, collectionIdMap);
|
|
2708
|
+
const downCode = generateOperationDownMigration(operation, collectionIdMap);
|
|
2709
|
+
const content = createMigrationFileStructure(upCode, downCode, normalizedConfig);
|
|
2710
|
+
const filename = generateCollectionMigrationFilename(operation);
|
|
2711
|
+
const filePath = writeMigrationFile(migrationDir, filename, content);
|
|
2712
|
+
filePaths.push(filePath);
|
|
2713
|
+
}
|
|
2714
|
+
return filePaths;
|
|
2559
2715
|
} catch (error) {
|
|
2560
2716
|
if (error instanceof MigrationGenerationError || error instanceof FileSystemError) {
|
|
2561
2717
|
throw error;
|
|
@@ -2572,7 +2728,7 @@ function generate(diff, config) {
|
|
|
2572
2728
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
2573
2729
|
function resolveCollectionIdToName(collectionId) {
|
|
2574
2730
|
if (collectionId === "_pb_users_auth_") {
|
|
2575
|
-
return "
|
|
2731
|
+
return "users";
|
|
2576
2732
|
}
|
|
2577
2733
|
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2578
2734
|
if (nameMatch) {
|
|
@@ -2580,6 +2736,39 @@ function resolveCollectionIdToName(collectionId) {
|
|
|
2580
2736
|
}
|
|
2581
2737
|
return collectionId;
|
|
2582
2738
|
}
|
|
2739
|
+
function extractFieldOptions2(pbField) {
|
|
2740
|
+
const options = {};
|
|
2741
|
+
if (pbField.options && typeof pbField.options === "object") {
|
|
2742
|
+
Object.assign(options, pbField.options);
|
|
2743
|
+
}
|
|
2744
|
+
const directOptionKeys = [
|
|
2745
|
+
"min",
|
|
2746
|
+
"max",
|
|
2747
|
+
"pattern",
|
|
2748
|
+
"noDecimal",
|
|
2749
|
+
// text/number fields
|
|
2750
|
+
"values",
|
|
2751
|
+
"maxSelect",
|
|
2752
|
+
// select fields
|
|
2753
|
+
"mimeTypes",
|
|
2754
|
+
"maxSize",
|
|
2755
|
+
"thumbs",
|
|
2756
|
+
"protected",
|
|
2757
|
+
// file fields
|
|
2758
|
+
"onCreate",
|
|
2759
|
+
"onUpdate",
|
|
2760
|
+
// autodate fields
|
|
2761
|
+
"exceptDomains",
|
|
2762
|
+
"onlyDomains"
|
|
2763
|
+
// email/url fields
|
|
2764
|
+
];
|
|
2765
|
+
for (const key of directOptionKeys) {
|
|
2766
|
+
if (pbField[key] !== void 0) {
|
|
2767
|
+
options[key] = pbField[key];
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
return options;
|
|
2771
|
+
}
|
|
2583
2772
|
function convertPocketBaseCollection(pbCollection) {
|
|
2584
2773
|
const fields = [];
|
|
2585
2774
|
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
@@ -2597,23 +2786,19 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2597
2786
|
type: pbField.type,
|
|
2598
2787
|
required: pbField.required || false
|
|
2599
2788
|
};
|
|
2600
|
-
field.options = pbField
|
|
2601
|
-
if (pbField.type === "select") {
|
|
2602
|
-
if (pbField.values && Array.isArray(pbField.values)) {
|
|
2603
|
-
field.options.values = pbField.values;
|
|
2604
|
-
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
2605
|
-
field.options.values = pbField.options.values;
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2789
|
+
field.options = extractFieldOptions2(pbField);
|
|
2608
2790
|
if (pbField.type === "relation") {
|
|
2609
2791
|
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
2610
|
-
const collectionName = resolveCollectionIdToName(collectionId);
|
|
2792
|
+
const collectionName = resolveCollectionIdToName(collectionId || "");
|
|
2611
2793
|
field.relation = {
|
|
2612
2794
|
collection: collectionName,
|
|
2613
2795
|
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
2614
2796
|
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
2615
2797
|
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
2616
2798
|
};
|
|
2799
|
+
delete field.options.maxSelect;
|
|
2800
|
+
delete field.options.minSelect;
|
|
2801
|
+
delete field.options.cascadeDelete;
|
|
2617
2802
|
}
|
|
2618
2803
|
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
2619
2804
|
if (Object.keys(field.options).length === 0) {
|
|
@@ -2627,17 +2812,21 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2627
2812
|
type: pbCollection.type || "base",
|
|
2628
2813
|
fields
|
|
2629
2814
|
};
|
|
2815
|
+
if (pbCollection.id) {
|
|
2816
|
+
schema.id = pbCollection.id;
|
|
2817
|
+
}
|
|
2630
2818
|
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
2631
2819
|
schema.indexes = pbCollection.indexes;
|
|
2632
2820
|
}
|
|
2633
|
-
const
|
|
2634
|
-
if (
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2821
|
+
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;
|
|
2822
|
+
if (hasAnyRule) {
|
|
2823
|
+
const rules = {};
|
|
2824
|
+
if (pbCollection.listRule !== void 0) rules.listRule = pbCollection.listRule;
|
|
2825
|
+
if (pbCollection.viewRule !== void 0) rules.viewRule = pbCollection.viewRule;
|
|
2826
|
+
if (pbCollection.createRule !== void 0) rules.createRule = pbCollection.createRule;
|
|
2827
|
+
if (pbCollection.updateRule !== void 0) rules.updateRule = pbCollection.updateRule;
|
|
2828
|
+
if (pbCollection.deleteRule !== void 0) rules.deleteRule = pbCollection.deleteRule;
|
|
2829
|
+
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
2641
2830
|
schema.rules = rules;
|
|
2642
2831
|
schema.permissions = { ...rules };
|
|
2643
2832
|
}
|
|
@@ -3576,15 +3765,25 @@ async function executeGenerate(options) {
|
|
|
3576
3765
|
process.exit(1);
|
|
3577
3766
|
}
|
|
3578
3767
|
logSection("\u{1F4DD} Generating Migration");
|
|
3579
|
-
const
|
|
3768
|
+
const migrationPaths = await withProgress(
|
|
3580
3769
|
"Creating migration file...",
|
|
3581
3770
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
3582
3771
|
);
|
|
3583
|
-
|
|
3772
|
+
if (migrationPaths.length === 0) {
|
|
3773
|
+
logWarning("No migration files were generated (no changes detected).");
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3776
|
+
if (migrationPaths.length === 1) {
|
|
3777
|
+
logSuccess(`Migration file created: ${path5.basename(migrationPaths[0])}`);
|
|
3778
|
+
} else {
|
|
3779
|
+
logSuccess(`Created ${migrationPaths.length} migration files`);
|
|
3780
|
+
}
|
|
3584
3781
|
logSection("\u2705 Next Steps");
|
|
3585
3782
|
console.log();
|
|
3586
|
-
console.log(" 1. Review the generated migration file:");
|
|
3587
|
-
|
|
3783
|
+
console.log(" 1. Review the generated migration file(s):");
|
|
3784
|
+
migrationPaths.forEach((migrationPath) => {
|
|
3785
|
+
console.log(` ${migrationPath}`);
|
|
3786
|
+
});
|
|
3588
3787
|
console.log();
|
|
3589
3788
|
console.log(" 2. Apply the migration by running PocketBase:");
|
|
3590
3789
|
console.log(" yarn pb");
|