pocketbase-zod-schema 0.7.0 → 0.7.2
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 +14 -0
- package/dist/cli/index.cjs +449 -50
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +449 -50
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +455 -53
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +455 -53
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/utils/index.cjs +8 -1
- package/dist/cli/utils/index.cjs.map +1 -1
- package/dist/cli/utils/index.d.cts +1 -1
- package/dist/cli/utils/index.d.ts +1 -1
- package/dist/cli/utils/index.js +8 -1
- package/dist/cli/utils/index.js.map +1 -1
- package/dist/index.cjs +90 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +87 -2
- package/dist/index.js.map +1 -1
- package/dist/migration/analyzer.cjs +87 -14
- package/dist/migration/analyzer.cjs.map +1 -1
- package/dist/migration/analyzer.d.cts +12 -4
- package/dist/migration/analyzer.d.ts +12 -4
- package/dist/migration/analyzer.js +87 -15
- package/dist/migration/analyzer.js.map +1 -1
- package/dist/migration/diff.cjs +64 -9
- package/dist/migration/diff.cjs.map +1 -1
- package/dist/migration/diff.d.cts +12 -2
- package/dist/migration/diff.d.ts +12 -2
- package/dist/migration/diff.js +64 -10
- package/dist/migration/diff.js.map +1 -1
- package/dist/migration/generator.cjs +206 -39
- package/dist/migration/generator.cjs.map +1 -1
- package/dist/migration/generator.d.cts +54 -2
- package/dist/migration/generator.d.ts +54 -2
- package/dist/migration/generator.js +203 -40
- package/dist/migration/generator.js.map +1 -1
- package/dist/migration/index.cjs +501 -63
- package/dist/migration/index.cjs.map +1 -1
- package/dist/migration/index.d.cts +2 -2
- package/dist/migration/index.d.ts +2 -2
- package/dist/migration/index.js +501 -63
- package/dist/migration/index.js.map +1 -1
- package/dist/migration/snapshot.cjs +147 -1
- package/dist/migration/snapshot.cjs.map +1 -1
- package/dist/migration/snapshot.d.cts +3 -1
- package/dist/migration/snapshot.d.ts +3 -1
- package/dist/migration/snapshot.js +147 -1
- package/dist/migration/snapshot.js.map +1 -1
- package/dist/migration/utils/index.d.cts +1 -1
- package/dist/migration/utils/index.d.ts +1 -1
- package/dist/schema.cjs +90 -1
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +128 -2
- package/dist/schema.d.ts +128 -2
- package/dist/schema.js +87 -2
- package/dist/schema.js.map +1 -1
- package/dist/server.cjs +545 -65
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +542 -66
- package/dist/server.js.map +1 -1
- package/dist/{types-CWHV6ATd.d.cts → types-CnzfX6JH.d.cts} +20 -2
- package/dist/{types-C2nGWHLV.d.ts → types-Do3jyFBm.d.ts} +20 -2
- package/package.json +1 -1
package/dist/server.cjs
CHANGED
|
@@ -481,13 +481,16 @@ function withIndexes(schema, indexes) {
|
|
|
481
481
|
return schema.describe(JSON.stringify(metadata));
|
|
482
482
|
}
|
|
483
483
|
function defineCollection(config) {
|
|
484
|
-
const { collectionName, schema, permissions, indexes, type, ...futureOptions } = config;
|
|
484
|
+
const { collectionName, schema, permissions, indexes, type, viewQuery, ...futureOptions } = config;
|
|
485
485
|
const metadata = {
|
|
486
486
|
collectionName
|
|
487
487
|
};
|
|
488
488
|
if (type) {
|
|
489
489
|
metadata.type = type;
|
|
490
490
|
}
|
|
491
|
+
if (viewQuery !== void 0) {
|
|
492
|
+
metadata.viewQuery = viewQuery;
|
|
493
|
+
}
|
|
491
494
|
if (permissions) {
|
|
492
495
|
metadata.permissions = permissions;
|
|
493
496
|
}
|
|
@@ -753,6 +756,88 @@ function GeoPointField() {
|
|
|
753
756
|
};
|
|
754
757
|
return schema.describe(JSON.stringify(metadata));
|
|
755
758
|
}
|
|
759
|
+
function dedentSql(value) {
|
|
760
|
+
const lines = value.replace(/\r\n/g, "\n").split("\n");
|
|
761
|
+
while (lines.length > 0 && lines[0].trim() === "") {
|
|
762
|
+
lines.shift();
|
|
763
|
+
}
|
|
764
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
|
|
765
|
+
lines.pop();
|
|
766
|
+
}
|
|
767
|
+
if (lines.length === 0) {
|
|
768
|
+
return "";
|
|
769
|
+
}
|
|
770
|
+
let minIndent = Infinity;
|
|
771
|
+
for (const line of lines) {
|
|
772
|
+
if (line.trim() === "") continue;
|
|
773
|
+
const indent = line.length - line.trimStart().length;
|
|
774
|
+
if (indent < minIndent) {
|
|
775
|
+
minIndent = indent;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
if (!Number.isFinite(minIndent) || minIndent === 0) {
|
|
779
|
+
return lines.map((line) => line.trimEnd()).join("\n");
|
|
780
|
+
}
|
|
781
|
+
return lines.map((line) => line.slice(minIndent).trimEnd()).join("\n");
|
|
782
|
+
}
|
|
783
|
+
function sql(strings, ...values) {
|
|
784
|
+
let result = "";
|
|
785
|
+
for (let i = 0; i < strings.length; i++) {
|
|
786
|
+
result += strings[i];
|
|
787
|
+
if (i < values.length) {
|
|
788
|
+
result += String(values[i]);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
return dedentSql(result);
|
|
792
|
+
}
|
|
793
|
+
function stripLeadingComments(query) {
|
|
794
|
+
let remaining = query.trim();
|
|
795
|
+
while (remaining.length > 0) {
|
|
796
|
+
if (remaining.startsWith("--")) {
|
|
797
|
+
const newline = remaining.indexOf("\n");
|
|
798
|
+
remaining = newline === -1 ? "" : remaining.slice(newline + 1).trim();
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
if (remaining.startsWith("/*")) {
|
|
802
|
+
const end = remaining.indexOf("*/");
|
|
803
|
+
remaining = end === -1 ? "" : remaining.slice(end + 2).trim();
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
break;
|
|
807
|
+
}
|
|
808
|
+
return remaining;
|
|
809
|
+
}
|
|
810
|
+
function validateViewQuery(collectionName, viewQuery) {
|
|
811
|
+
if (typeof viewQuery !== "string" || viewQuery.trim() === "") {
|
|
812
|
+
throw new Error(
|
|
813
|
+
`View collection "${collectionName}" requires a non-empty viewQuery. Provide the SQL SELECT statement backing the view.`
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
const body = stripLeadingComments(viewQuery);
|
|
817
|
+
if (!/^(select|with)\b/i.test(body)) {
|
|
818
|
+
throw new Error(
|
|
819
|
+
`View collection "${collectionName}" has an invalid viewQuery: it must start with SELECT or WITH. Received: ${body.slice(0, 40)}${body.length > 40 ? "..." : ""}`
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
function defineView(config) {
|
|
824
|
+
const { collectionName, schema, viewQuery, permissions } = config;
|
|
825
|
+
validateViewQuery(collectionName, viewQuery);
|
|
826
|
+
return defineCollection({
|
|
827
|
+
collectionName,
|
|
828
|
+
schema,
|
|
829
|
+
type: "view",
|
|
830
|
+
viewQuery,
|
|
831
|
+
// Write rules are always locked for views - PocketBase rejects anything else
|
|
832
|
+
permissions: {
|
|
833
|
+
listRule: permissions?.listRule ?? null,
|
|
834
|
+
viewRule: permissions?.viewRule ?? null,
|
|
835
|
+
createRule: null,
|
|
836
|
+
updateRule: null,
|
|
837
|
+
deleteRule: null
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
}
|
|
756
841
|
|
|
757
842
|
// src/utils/permission-templates.ts
|
|
758
843
|
var PermissionTemplates = {
|
|
@@ -2299,13 +2384,26 @@ function extractCollectionTypeFromSchema(zodSchema) {
|
|
|
2299
2384
|
}
|
|
2300
2385
|
try {
|
|
2301
2386
|
const metadata = JSON.parse(zodSchema.description);
|
|
2302
|
-
if (metadata.type === "base" || metadata.type === "auth") {
|
|
2387
|
+
if (metadata.type === "base" || metadata.type === "auth" || metadata.type === "view") {
|
|
2303
2388
|
return metadata.type;
|
|
2304
2389
|
}
|
|
2305
2390
|
} catch {
|
|
2306
2391
|
}
|
|
2307
2392
|
return null;
|
|
2308
2393
|
}
|
|
2394
|
+
function extractViewQueryFromSchema(zodSchema) {
|
|
2395
|
+
if (!zodSchema.description) {
|
|
2396
|
+
return null;
|
|
2397
|
+
}
|
|
2398
|
+
try {
|
|
2399
|
+
const metadata = JSON.parse(zodSchema.description);
|
|
2400
|
+
if (typeof metadata.viewQuery === "string") {
|
|
2401
|
+
return metadata.viewQuery;
|
|
2402
|
+
}
|
|
2403
|
+
} catch {
|
|
2404
|
+
}
|
|
2405
|
+
return null;
|
|
2406
|
+
}
|
|
2309
2407
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema", "Collection"]) {
|
|
2310
2408
|
const result = {};
|
|
2311
2409
|
if (module.default instanceof zod.z.ZodObject) {
|
|
@@ -2464,6 +2562,15 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
|
|
|
2464
2562
|
const rawFields = extractFieldDefinitions(zodSchema);
|
|
2465
2563
|
const explicitType = extractCollectionTypeFromSchema(zodSchema);
|
|
2466
2564
|
const collectionType = explicitType ?? (isAuthCollection(rawFields) ? "auth" : "base");
|
|
2565
|
+
const isView = collectionType === "view";
|
|
2566
|
+
const viewQuery = extractViewQueryFromSchema(zodSchema);
|
|
2567
|
+
if (isView) {
|
|
2568
|
+
validateViewQuery(collectionName, viewQuery);
|
|
2569
|
+
} else if (viewQuery !== null) {
|
|
2570
|
+
console.warn(
|
|
2571
|
+
`[${collectionName}] viewQuery is only used by view collections and will be ignored. Use defineView() or set type: "view" to define a view collection.`
|
|
2572
|
+
);
|
|
2573
|
+
}
|
|
2467
2574
|
const fields = rawFields.filter((f) => !["created", "updated"].includes(f.name)).map(({ name, zodType }) => buildFieldDefinition(name, zodType));
|
|
2468
2575
|
if (collectionType === "auth") {
|
|
2469
2576
|
const authSystemFields = [
|
|
@@ -2523,26 +2630,43 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
|
|
|
2523
2630
|
}
|
|
2524
2631
|
}
|
|
2525
2632
|
const indexes = extractIndexes(zodSchema) || [];
|
|
2633
|
+
if (isView && indexes.length > 0) {
|
|
2634
|
+
throw new Error(
|
|
2635
|
+
`View collection "${collectionName}" cannot declare indexes. PocketBase view collections are backed by a SQL query and do not support indexes.`
|
|
2636
|
+
);
|
|
2637
|
+
}
|
|
2526
2638
|
const permissionAnalyzer = new PermissionAnalyzer();
|
|
2527
2639
|
let permissions = void 0;
|
|
2528
2640
|
const schemaDescription = zodSchema.description;
|
|
2529
2641
|
const extractedPermissions = permissionAnalyzer.extractPermissions(schemaDescription);
|
|
2530
2642
|
if (extractedPermissions) {
|
|
2531
2643
|
const resolvedPermissions = permissionAnalyzer.resolvePermissions(extractedPermissions);
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
console.error(`[${collectionName}] Permission validation failed for ${ruleType}:`);
|
|
2541
|
-
result.errors.forEach((error) => console.error(` - ${error}`));
|
|
2644
|
+
if (isView) {
|
|
2645
|
+
for (const ruleType of ["createRule", "updateRule", "deleteRule", "manageRule"]) {
|
|
2646
|
+
if (resolvedPermissions[ruleType]) {
|
|
2647
|
+
console.warn(
|
|
2648
|
+
`[${collectionName}] ${ruleType} is not supported on view collections and will be set to null.`
|
|
2649
|
+
);
|
|
2650
|
+
}
|
|
2651
|
+
resolvedPermissions[ruleType] = null;
|
|
2542
2652
|
}
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2653
|
+
}
|
|
2654
|
+
if (!isView) {
|
|
2655
|
+
const validationResults = permissionAnalyzer.validatePermissions(
|
|
2656
|
+
collectionName,
|
|
2657
|
+
resolvedPermissions,
|
|
2658
|
+
fields,
|
|
2659
|
+
collectionType === "auth"
|
|
2660
|
+
);
|
|
2661
|
+
for (const [ruleType, result] of validationResults) {
|
|
2662
|
+
if (!result.valid) {
|
|
2663
|
+
console.error(`[${collectionName}] Permission validation failed for ${ruleType}:`);
|
|
2664
|
+
result.errors.forEach((error) => console.error(` - ${error}`));
|
|
2665
|
+
}
|
|
2666
|
+
if (result.warnings.length > 0) {
|
|
2667
|
+
console.warn(`[${collectionName}] Permission warnings for ${ruleType}:`);
|
|
2668
|
+
result.warnings.forEach((warning) => console.warn(` - ${warning}`));
|
|
2669
|
+
}
|
|
2546
2670
|
}
|
|
2547
2671
|
}
|
|
2548
2672
|
permissions = permissionAnalyzer.mergeWithDefaults(resolvedPermissions);
|
|
@@ -2563,6 +2687,9 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
|
|
|
2563
2687
|
},
|
|
2564
2688
|
permissions
|
|
2565
2689
|
};
|
|
2690
|
+
if (isView) {
|
|
2691
|
+
collectionSchema.viewQuery = viewQuery;
|
|
2692
|
+
}
|
|
2566
2693
|
return collectionSchema;
|
|
2567
2694
|
}
|
|
2568
2695
|
var tsxLoaderRegistered = false;
|
|
@@ -2844,8 +2971,9 @@ function convertPocketBaseField(pbField) {
|
|
|
2844
2971
|
}
|
|
2845
2972
|
function convertPocketBaseCollection(pbCollection) {
|
|
2846
2973
|
const fields = [];
|
|
2974
|
+
const isView = pbCollection.type === "view";
|
|
2847
2975
|
const systemFieldNames = ["id", "created", "updated", "collectionId", "collectionName", "expand"];
|
|
2848
|
-
if (pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
2976
|
+
if (!isView && pbCollection.fields && Array.isArray(pbCollection.fields)) {
|
|
2849
2977
|
for (const pbField of pbCollection.fields) {
|
|
2850
2978
|
if (pbField.system || systemFieldNames.includes(pbField.name)) {
|
|
2851
2979
|
const isAuthSystemField = pbCollection.type === "auth" && ["email", "emailVisibility", "verified", "password", "tokenKey"].includes(pbField.name);
|
|
@@ -2865,6 +2993,9 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2865
2993
|
if (pbCollection.id) {
|
|
2866
2994
|
schema.id = pbCollection.id;
|
|
2867
2995
|
}
|
|
2996
|
+
if (typeof pbCollection.viewQuery === "string") {
|
|
2997
|
+
schema.viewQuery = dedentSql(pbCollection.viewQuery);
|
|
2998
|
+
}
|
|
2868
2999
|
if (pbCollection.indexes && Array.isArray(pbCollection.indexes)) {
|
|
2869
3000
|
schema.indexes = pbCollection.indexes;
|
|
2870
3001
|
}
|
|
@@ -2966,6 +3097,24 @@ function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
|
2966
3097
|
return [];
|
|
2967
3098
|
}
|
|
2968
3099
|
}
|
|
3100
|
+
function skipTemplateLiteral(content, start) {
|
|
3101
|
+
let i = start + 1;
|
|
3102
|
+
while (i < content.length) {
|
|
3103
|
+
const char = content[i];
|
|
3104
|
+
if (char === "\\") {
|
|
3105
|
+
i += 2;
|
|
3106
|
+
continue;
|
|
3107
|
+
}
|
|
3108
|
+
if (char === "`") {
|
|
3109
|
+
return i + 1;
|
|
3110
|
+
}
|
|
3111
|
+
i++;
|
|
3112
|
+
}
|
|
3113
|
+
return i;
|
|
3114
|
+
}
|
|
3115
|
+
function unescapeTemplateLiteral(raw) {
|
|
3116
|
+
return raw.replace(/\\(`|\$\{|\\)/g, "$1");
|
|
3117
|
+
}
|
|
2969
3118
|
function parseMigrationOperationsFromContent(content) {
|
|
2970
3119
|
const collectionsToCreate = [];
|
|
2971
3120
|
const collectionsToDelete = [];
|
|
@@ -3054,6 +3203,10 @@ function parseMigrationOperationsFromContent(content) {
|
|
|
3054
3203
|
while (i < content.length && bCount > 0) {
|
|
3055
3204
|
const char = content[i];
|
|
3056
3205
|
const prev = i > 0 ? content[i - 1] : "";
|
|
3206
|
+
if (!inStr && char === "`") {
|
|
3207
|
+
i = skipTemplateLiteral(content, i);
|
|
3208
|
+
continue;
|
|
3209
|
+
}
|
|
3057
3210
|
if (!inStr && (char === '"' || char === "'")) {
|
|
3058
3211
|
inStr = true;
|
|
3059
3212
|
strChar = char;
|
|
@@ -3243,6 +3396,95 @@ function parseMigrationOperationsFromContent(content) {
|
|
|
3243
3396
|
}
|
|
3244
3397
|
}
|
|
3245
3398
|
}
|
|
3399
|
+
const viewQueryRegex = /(\w+)\.viewQuery\s*=\s*/g;
|
|
3400
|
+
let viewQueryMatch;
|
|
3401
|
+
while ((viewQueryMatch = viewQueryRegex.exec(content)) !== null) {
|
|
3402
|
+
const varInfo = variables.get(viewQueryMatch[1]);
|
|
3403
|
+
if (!varInfo || varInfo.type !== "collection") continue;
|
|
3404
|
+
const valueStart = viewQueryMatch.index + viewQueryMatch[0].length;
|
|
3405
|
+
if (content[valueStart] === "`") {
|
|
3406
|
+
const end = skipTemplateLiteral(content, valueStart);
|
|
3407
|
+
const raw = content.substring(valueStart + 1, end - 1);
|
|
3408
|
+
getUpdate(varInfo.name).viewQuery = dedentSql(unescapeTemplateLiteral(raw));
|
|
3409
|
+
viewQueryRegex.lastIndex = end;
|
|
3410
|
+
} else {
|
|
3411
|
+
const terminator = content.indexOf(";", valueStart);
|
|
3412
|
+
const valueStr = content.substring(valueStart, terminator === -1 ? content.length : terminator);
|
|
3413
|
+
try {
|
|
3414
|
+
getUpdate(varInfo.name).viewQuery = dedentSql(new Function("app", `return ${valueStr}`)(mockApp));
|
|
3415
|
+
} catch {
|
|
3416
|
+
getUpdate(varInfo.name).viewQuery = dedentSql(valueStr.trim());
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
const unmarshalRegex = /unmarshal\s*\(/g;
|
|
3421
|
+
let unmarshalMatch;
|
|
3422
|
+
while ((unmarshalMatch = unmarshalRegex.exec(content)) !== null) {
|
|
3423
|
+
let i = unmarshalMatch.index + unmarshalMatch[0].length;
|
|
3424
|
+
while (i < content.length && /\s/.test(content[i])) i++;
|
|
3425
|
+
if (content[i] !== "{") continue;
|
|
3426
|
+
const objStart = i;
|
|
3427
|
+
let braceCount = 1;
|
|
3428
|
+
let inStr = false;
|
|
3429
|
+
let strChar = null;
|
|
3430
|
+
i++;
|
|
3431
|
+
while (i < content.length && braceCount > 0) {
|
|
3432
|
+
const ch = content[i];
|
|
3433
|
+
const prev = i > 0 ? content[i - 1] : "";
|
|
3434
|
+
if (!inStr && ch === "`") {
|
|
3435
|
+
i = skipTemplateLiteral(content, i);
|
|
3436
|
+
continue;
|
|
3437
|
+
}
|
|
3438
|
+
if (!inStr && (ch === '"' || ch === "'")) {
|
|
3439
|
+
inStr = true;
|
|
3440
|
+
strChar = ch;
|
|
3441
|
+
} else if (inStr && ch === strChar && prev !== "\\") {
|
|
3442
|
+
inStr = false;
|
|
3443
|
+
strChar = null;
|
|
3444
|
+
}
|
|
3445
|
+
if (!inStr) {
|
|
3446
|
+
if (ch === "{") braceCount++;
|
|
3447
|
+
if (ch === "}") braceCount--;
|
|
3448
|
+
}
|
|
3449
|
+
i++;
|
|
3450
|
+
}
|
|
3451
|
+
if (braceCount !== 0) continue;
|
|
3452
|
+
const objStr = content.substring(objStart, i);
|
|
3453
|
+
while (i < content.length && /[\s,]/.test(content[i])) i++;
|
|
3454
|
+
const varStart = i;
|
|
3455
|
+
while (i < content.length && /\w/.test(content[i])) i++;
|
|
3456
|
+
const colVarName = content.substring(varStart, i);
|
|
3457
|
+
const colInfo = variables.get(colVarName);
|
|
3458
|
+
if (!colInfo || colInfo.type !== "collection") continue;
|
|
3459
|
+
const keyValRegex = /"(\w+Rule)"\s*:\s*([^,}\n]+)/g;
|
|
3460
|
+
let kvMatch;
|
|
3461
|
+
while ((kvMatch = keyValRegex.exec(objStr)) !== null) {
|
|
3462
|
+
const ruleKey = kvMatch[1];
|
|
3463
|
+
const valStr = kvMatch[2].trim();
|
|
3464
|
+
try {
|
|
3465
|
+
const value = new Function("app", `return ${valStr}`)(mockApp);
|
|
3466
|
+
getUpdate(colInfo.name).rulesToUpdate[ruleKey] = value;
|
|
3467
|
+
} catch {
|
|
3468
|
+
getUpdate(colInfo.name).rulesToUpdate[ruleKey] = valStr;
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
const viewQueryKey = objStr.match(/"viewQuery"\s*:\s*/);
|
|
3472
|
+
if (viewQueryKey) {
|
|
3473
|
+
const valueStart = viewQueryKey.index + viewQueryKey[0].length;
|
|
3474
|
+
if (objStr[valueStart] === "`") {
|
|
3475
|
+
const end = skipTemplateLiteral(objStr, valueStart);
|
|
3476
|
+
const raw = objStr.substring(valueStart + 1, end - 1);
|
|
3477
|
+
getUpdate(colInfo.name).viewQuery = dedentSql(unescapeTemplateLiteral(raw));
|
|
3478
|
+
} else {
|
|
3479
|
+
const valStr = objStr.substring(valueStart).replace(/[,}\s]+$/, "");
|
|
3480
|
+
try {
|
|
3481
|
+
getUpdate(colInfo.name).viewQuery = dedentSql(new Function("app", `return ${valStr}`)(mockApp));
|
|
3482
|
+
} catch {
|
|
3483
|
+
getUpdate(colInfo.name).viewQuery = dedentSql(valStr);
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3246
3488
|
const idxPushRegex = /(\w+)\.indexes\.push\s*\(/g;
|
|
3247
3489
|
let match;
|
|
3248
3490
|
while ((match = idxPushRegex.exec(content)) !== null) {
|
|
@@ -3372,6 +3614,10 @@ function parseMigrationOperations(migrationContent) {
|
|
|
3372
3614
|
while (i < migrationContent.length && braceCount > 0) {
|
|
3373
3615
|
const char = migrationContent[i];
|
|
3374
3616
|
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
3617
|
+
if (!inString && char === "`") {
|
|
3618
|
+
i = skipTemplateLiteral(migrationContent, i);
|
|
3619
|
+
continue;
|
|
3620
|
+
}
|
|
3375
3621
|
if (!inString && (char === '"' || char === "'")) {
|
|
3376
3622
|
inString = true;
|
|
3377
3623
|
stringChar = char;
|
|
@@ -3707,6 +3953,9 @@ function applyMigrationOperations(snapshot, operations) {
|
|
|
3707
3953
|
collection.indexes = collection.indexes.filter((idx) => !update.indexesToRemove.includes(idx));
|
|
3708
3954
|
}
|
|
3709
3955
|
}
|
|
3956
|
+
if (update.viewQuery !== void 0) {
|
|
3957
|
+
collection.viewQuery = update.viewQuery;
|
|
3958
|
+
}
|
|
3710
3959
|
if (Object.keys(update.rulesToUpdate).length > 0) {
|
|
3711
3960
|
if (!collection.rules) collection.rules = {};
|
|
3712
3961
|
if (!collection.permissions) collection.permissions = {};
|
|
@@ -4326,7 +4575,45 @@ function compareCollectionFields(currentCollection, previousCollection, config,
|
|
|
4326
4575
|
fieldsToRemove = fieldsToRemove.filter((_, index) => !processedRemoveIndices.has(index));
|
|
4327
4576
|
return { fieldsToAdd, fieldsToRemove, fieldsToModify };
|
|
4328
4577
|
}
|
|
4578
|
+
function normalizeSql(query) {
|
|
4579
|
+
if (!query) {
|
|
4580
|
+
return "";
|
|
4581
|
+
}
|
|
4582
|
+
return query.split("\n").map((line) => line.trim()).join(" ").replace(/\s+/g, " ").trim();
|
|
4583
|
+
}
|
|
4584
|
+
function compareViewQuery(currentCollection, previousCollection) {
|
|
4585
|
+
const newValue = currentCollection.viewQuery;
|
|
4586
|
+
if (typeof newValue !== "string") {
|
|
4587
|
+
return void 0;
|
|
4588
|
+
}
|
|
4589
|
+
if (normalizeSql(newValue) === normalizeSql(previousCollection.viewQuery)) {
|
|
4590
|
+
return void 0;
|
|
4591
|
+
}
|
|
4592
|
+
return {
|
|
4593
|
+
oldValue: previousCollection.viewQuery ?? null,
|
|
4594
|
+
newValue
|
|
4595
|
+
};
|
|
4596
|
+
}
|
|
4329
4597
|
function buildCollectionModification(currentCollection, previousCollection, config, collectionIdToName) {
|
|
4598
|
+
const isView = currentCollection.type === "view" || previousCollection.type === "view";
|
|
4599
|
+
if (isView) {
|
|
4600
|
+
return {
|
|
4601
|
+
collection: currentCollection.name,
|
|
4602
|
+
fieldsToAdd: [],
|
|
4603
|
+
fieldsToRemove: [],
|
|
4604
|
+
fieldsToModify: [],
|
|
4605
|
+
indexesToAdd: [],
|
|
4606
|
+
indexesToRemove: [],
|
|
4607
|
+
rulesToUpdate: compareRules(
|
|
4608
|
+
currentCollection.rules,
|
|
4609
|
+
previousCollection.rules,
|
|
4610
|
+
currentCollection.permissions,
|
|
4611
|
+
previousCollection.permissions
|
|
4612
|
+
),
|
|
4613
|
+
permissionsToUpdate: comparePermissions(currentCollection.permissions, previousCollection.permissions),
|
|
4614
|
+
viewQueryUpdate: compareViewQuery(currentCollection, previousCollection)
|
|
4615
|
+
};
|
|
4616
|
+
}
|
|
4330
4617
|
const { fieldsToAdd, fieldsToRemove, fieldsToModify } = compareCollectionFields(
|
|
4331
4618
|
currentCollection,
|
|
4332
4619
|
previousCollection,
|
|
@@ -4358,6 +4645,9 @@ function detectDestructiveChanges(diff, config) {
|
|
|
4358
4645
|
const destructiveChanges = [];
|
|
4359
4646
|
const mergedConfig = mergeConfig3(config);
|
|
4360
4647
|
for (const collection of diff.collectionsToDelete) {
|
|
4648
|
+
if (collection.type === "view") {
|
|
4649
|
+
continue;
|
|
4650
|
+
}
|
|
4361
4651
|
destructiveChanges.push({
|
|
4362
4652
|
type: "collection_delete",
|
|
4363
4653
|
severity: "high",
|
|
@@ -4445,7 +4735,11 @@ function categorizeChangesBySeverity(diff, _config) {
|
|
|
4445
4735
|
const destructive = [];
|
|
4446
4736
|
const nonDestructive = [];
|
|
4447
4737
|
for (const collection of diff.collectionsToDelete) {
|
|
4448
|
-
|
|
4738
|
+
if (collection.type === "view") {
|
|
4739
|
+
nonDestructive.push(`Delete view collection: ${collection.name}`);
|
|
4740
|
+
} else {
|
|
4741
|
+
destructive.push(`Delete collection: ${collection.name}`);
|
|
4742
|
+
}
|
|
4449
4743
|
}
|
|
4450
4744
|
for (const collection of diff.collectionsToCreate) {
|
|
4451
4745
|
nonDestructive.push(`Create collection: ${collection.name}`);
|
|
@@ -4480,6 +4774,9 @@ function categorizeChangesBySeverity(diff, _config) {
|
|
|
4480
4774
|
for (const rule of modification.rulesToUpdate) {
|
|
4481
4775
|
nonDestructive.push(`Update rule: ${collectionName}.${rule.ruleType}`);
|
|
4482
4776
|
}
|
|
4777
|
+
if (modification.viewQueryUpdate) {
|
|
4778
|
+
nonDestructive.push(`Update view query: ${collectionName}`);
|
|
4779
|
+
}
|
|
4483
4780
|
}
|
|
4484
4781
|
return { destructive, nonDestructive };
|
|
4485
4782
|
}
|
|
@@ -4492,6 +4789,7 @@ function generateChangeSummary(diff, config) {
|
|
|
4492
4789
|
let indexChanges = 0;
|
|
4493
4790
|
let ruleChanges = 0;
|
|
4494
4791
|
let permissionChanges = 0;
|
|
4792
|
+
let viewQueryChanges = 0;
|
|
4495
4793
|
for (const modification of diff.collectionsToModify) {
|
|
4496
4794
|
fieldsToAdd += modification.fieldsToAdd.length;
|
|
4497
4795
|
fieldsToRemove += modification.fieldsToRemove.length;
|
|
@@ -4499,6 +4797,9 @@ function generateChangeSummary(diff, config) {
|
|
|
4499
4797
|
indexChanges += modification.indexesToAdd.length + modification.indexesToRemove.length;
|
|
4500
4798
|
ruleChanges += modification.rulesToUpdate.length;
|
|
4501
4799
|
permissionChanges += modification.permissionsToUpdate.length;
|
|
4800
|
+
if (modification.viewQueryUpdate) {
|
|
4801
|
+
viewQueryChanges += 1;
|
|
4802
|
+
}
|
|
4502
4803
|
}
|
|
4503
4804
|
return {
|
|
4504
4805
|
totalChanges: diff.collectionsToCreate.length + diff.collectionsToDelete.length + diff.collectionsToModify.length,
|
|
@@ -4511,6 +4812,7 @@ function generateChangeSummary(diff, config) {
|
|
|
4511
4812
|
indexChanges,
|
|
4512
4813
|
ruleChanges,
|
|
4513
4814
|
permissionChanges,
|
|
4815
|
+
viewQueryChanges,
|
|
4514
4816
|
destructiveChanges,
|
|
4515
4817
|
nonDestructiveChanges: nonDestructive
|
|
4516
4818
|
};
|
|
@@ -4540,12 +4842,11 @@ function filterDiff(diff, options) {
|
|
|
4540
4842
|
});
|
|
4541
4843
|
let collectionsToDelete = diff.collectionsToDelete;
|
|
4542
4844
|
if (skipDestructive) {
|
|
4543
|
-
collectionsToDelete =
|
|
4544
|
-
} else {
|
|
4545
|
-
collectionsToDelete = collectionsToDelete.filter((col) => {
|
|
4546
|
-
return matchesPattern(col.name, patterns);
|
|
4547
|
-
});
|
|
4845
|
+
collectionsToDelete = collectionsToDelete.filter((col) => col.type === "view");
|
|
4548
4846
|
}
|
|
4847
|
+
collectionsToDelete = collectionsToDelete.filter((col) => {
|
|
4848
|
+
return matchesPattern(col.name, patterns);
|
|
4849
|
+
});
|
|
4549
4850
|
const collectionsToModify = diff.collectionsToModify.map((mod) => {
|
|
4550
4851
|
const collectionMatches = matchesPattern(mod.collection, patterns);
|
|
4551
4852
|
const fieldsToAdd = mod.fieldsToAdd.filter((field) => {
|
|
@@ -4570,6 +4871,7 @@ function filterDiff(diff, options) {
|
|
|
4570
4871
|
const indexesToRemove = collectionMatches ? mod.indexesToRemove : [];
|
|
4571
4872
|
const rulesToUpdate = collectionMatches ? mod.rulesToUpdate : [];
|
|
4572
4873
|
const permissionsToUpdate = collectionMatches ? mod.permissionsToUpdate : [];
|
|
4874
|
+
const viewQueryUpdate = collectionMatches ? mod.viewQueryUpdate : void 0;
|
|
4573
4875
|
return {
|
|
4574
4876
|
...mod,
|
|
4575
4877
|
fieldsToAdd,
|
|
@@ -4578,10 +4880,11 @@ function filterDiff(diff, options) {
|
|
|
4578
4880
|
indexesToAdd,
|
|
4579
4881
|
indexesToRemove,
|
|
4580
4882
|
rulesToUpdate,
|
|
4581
|
-
permissionsToUpdate
|
|
4883
|
+
permissionsToUpdate,
|
|
4884
|
+
viewQueryUpdate
|
|
4582
4885
|
};
|
|
4583
4886
|
}).filter((mod) => {
|
|
4584
|
-
return mod.fieldsToAdd.length > 0 || mod.fieldsToRemove.length > 0 || mod.fieldsToModify.length > 0 || mod.indexesToAdd.length > 0 || mod.indexesToRemove.length > 0 || mod.rulesToUpdate.length > 0 || mod.permissionsToUpdate.length > 0;
|
|
4887
|
+
return mod.fieldsToAdd.length > 0 || mod.fieldsToRemove.length > 0 || mod.fieldsToModify.length > 0 || mod.indexesToAdd.length > 0 || mod.indexesToRemove.length > 0 || mod.rulesToUpdate.length > 0 || mod.permissionsToUpdate.length > 0 || mod.viewQueryUpdate !== void 0;
|
|
4585
4888
|
});
|
|
4586
4889
|
return {
|
|
4587
4890
|
...diff,
|
|
@@ -4593,7 +4896,7 @@ function filterDiff(diff, options) {
|
|
|
4593
4896
|
|
|
4594
4897
|
// src/migration/diff/index.ts
|
|
4595
4898
|
function hasChanges(modification) {
|
|
4596
|
-
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;
|
|
4899
|
+
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 || modification.viewQueryUpdate !== void 0;
|
|
4597
4900
|
}
|
|
4598
4901
|
function aggregateChanges(currentSchema, previousSnapshot, config) {
|
|
4599
4902
|
const collectionIdToName = /* @__PURE__ */ new Map();
|
|
@@ -4808,6 +5111,13 @@ function formatValue(value) {
|
|
|
4808
5111
|
}
|
|
4809
5112
|
return String(value);
|
|
4810
5113
|
}
|
|
5114
|
+
function formatSqlTemplate(query, indent = " ") {
|
|
5115
|
+
const escaped = query.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
5116
|
+
const body = escaped.split("\n").map((line) => line.trim() === "" ? "" : `${indent}${line}`).join("\n");
|
|
5117
|
+
return `\`
|
|
5118
|
+
${body}
|
|
5119
|
+
${indent.slice(0, -2)}\``;
|
|
5120
|
+
}
|
|
4811
5121
|
function getFieldConstructorName(fieldType) {
|
|
4812
5122
|
const constructorMap = {
|
|
4813
5123
|
text: "TextField",
|
|
@@ -4846,6 +5156,36 @@ function getSystemFields() {
|
|
|
4846
5156
|
}
|
|
4847
5157
|
];
|
|
4848
5158
|
}
|
|
5159
|
+
function getSystemTimestampFields() {
|
|
5160
|
+
return [
|
|
5161
|
+
{
|
|
5162
|
+
name: "created",
|
|
5163
|
+
id: "autodate2990389176",
|
|
5164
|
+
type: "autodate",
|
|
5165
|
+
required: false,
|
|
5166
|
+
options: {
|
|
5167
|
+
hidden: false,
|
|
5168
|
+
onCreate: true,
|
|
5169
|
+
onUpdate: false,
|
|
5170
|
+
presentable: false,
|
|
5171
|
+
system: true
|
|
5172
|
+
}
|
|
5173
|
+
},
|
|
5174
|
+
{
|
|
5175
|
+
name: "updated",
|
|
5176
|
+
id: "autodate3332085495",
|
|
5177
|
+
type: "autodate",
|
|
5178
|
+
required: false,
|
|
5179
|
+
options: {
|
|
5180
|
+
hidden: false,
|
|
5181
|
+
onCreate: true,
|
|
5182
|
+
onUpdate: true,
|
|
5183
|
+
presentable: false,
|
|
5184
|
+
system: true
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
];
|
|
5188
|
+
}
|
|
4849
5189
|
function getAuthSystemFields() {
|
|
4850
5190
|
return [
|
|
4851
5191
|
{
|
|
@@ -5138,6 +5478,15 @@ function generateCollectionRules(rules, collectionType = "base") {
|
|
|
5138
5478
|
if (!rules) {
|
|
5139
5479
|
return "";
|
|
5140
5480
|
}
|
|
5481
|
+
if (collectionType === "view") {
|
|
5482
|
+
return [
|
|
5483
|
+
`"listRule": ${formatValue(rules.listRule ?? null)}`,
|
|
5484
|
+
`"viewRule": ${formatValue(rules.viewRule ?? null)}`,
|
|
5485
|
+
`"createRule": null`,
|
|
5486
|
+
`"updateRule": null`,
|
|
5487
|
+
`"deleteRule": null`
|
|
5488
|
+
].join(",\n ");
|
|
5489
|
+
}
|
|
5141
5490
|
const parts = [];
|
|
5142
5491
|
if (rules.listRule !== void 0) {
|
|
5143
5492
|
parts.push(`"listRule": ${formatValue(rules.listRule)}`);
|
|
@@ -5163,6 +5512,15 @@ function generateCollectionPermissions(permissions, collectionType = "base") {
|
|
|
5163
5512
|
if (!permissions) {
|
|
5164
5513
|
return "";
|
|
5165
5514
|
}
|
|
5515
|
+
if (collectionType === "view") {
|
|
5516
|
+
return [
|
|
5517
|
+
`"listRule": ${formatValue(permissions.listRule ?? null)}`,
|
|
5518
|
+
`"viewRule": ${formatValue(permissions.viewRule ?? null)}`,
|
|
5519
|
+
`"createRule": null`,
|
|
5520
|
+
`"updateRule": null`,
|
|
5521
|
+
`"deleteRule": null`
|
|
5522
|
+
].join(",\n ");
|
|
5523
|
+
}
|
|
5166
5524
|
const parts = [];
|
|
5167
5525
|
if (permissions.listRule !== void 0) {
|
|
5168
5526
|
parts.push(`"listRule": ${formatValue(permissions.listRule)}`);
|
|
@@ -5200,6 +5558,28 @@ function generatePermissionUpdate(collectionName, ruleType, newValue, varName, i
|
|
|
5200
5558
|
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
5201
5559
|
return lines.join("\n");
|
|
5202
5560
|
}
|
|
5561
|
+
function generateViewQueryUpdate(collectionName, viewQuery, varName, isLast = false, collectionIdMap) {
|
|
5562
|
+
const lines = [];
|
|
5563
|
+
const collectionVar = varName || `collection_${collectionName}_viewQuery`;
|
|
5564
|
+
lines.push(` const ${collectionVar} = ${generateFindCollectionCode(collectionName, collectionIdMap)};`);
|
|
5565
|
+
lines.push(` unmarshal({`);
|
|
5566
|
+
lines.push(` "viewQuery": ${formatSqlTemplate(viewQuery, " ")},`);
|
|
5567
|
+
lines.push(` }, ${collectionVar})`);
|
|
5568
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
5569
|
+
return lines.join("\n");
|
|
5570
|
+
}
|
|
5571
|
+
function generateGroupedRuleUpdates(collectionName, entries, varSuffix, isLast = false, collectionIdMap) {
|
|
5572
|
+
const collectionVar = `collection_${collectionName}_${varSuffix}`;
|
|
5573
|
+
const lines = [];
|
|
5574
|
+
lines.push(` const ${collectionVar} = ${generateFindCollectionCode(collectionName, collectionIdMap)};`);
|
|
5575
|
+
lines.push(` unmarshal({`);
|
|
5576
|
+
for (const entry of entries) {
|
|
5577
|
+
lines.push(` "${entry.ruleType}": ${formatValue(entry.value)},`);
|
|
5578
|
+
}
|
|
5579
|
+
lines.push(` }, ${collectionVar})`);
|
|
5580
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
5581
|
+
return lines.join("\n");
|
|
5582
|
+
}
|
|
5203
5583
|
|
|
5204
5584
|
// src/migration/generator/collections.ts
|
|
5205
5585
|
function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
|
|
@@ -5218,16 +5598,24 @@ function generateCollectionCreation(collection, varName = "collection", isLast =
|
|
|
5218
5598
|
} else if (rulesCode) {
|
|
5219
5599
|
lines.push(` ${rulesCode},`);
|
|
5220
5600
|
}
|
|
5601
|
+
if (collection.type === "view") {
|
|
5602
|
+
lines.push(` "viewQuery": ${formatSqlTemplate(collection.viewQuery ?? "")},`);
|
|
5603
|
+
lines.push(` });`);
|
|
5604
|
+
lines.push(``);
|
|
5605
|
+
lines.push(isLast ? ` return app.save(${varName});` : ` app.save(${varName});`);
|
|
5606
|
+
return lines.join("\n");
|
|
5607
|
+
}
|
|
5221
5608
|
const systemFieldNames = ["created", "updated", "id"];
|
|
5222
5609
|
if (collection.type === "auth") {
|
|
5223
5610
|
systemFieldNames.push(...getAuthSystemFields().map((f) => f.name));
|
|
5224
5611
|
}
|
|
5225
5612
|
const userFields = collection.fields.filter((f) => !systemFieldNames.includes(f.name));
|
|
5226
|
-
const allFields = [...getSystemFields()
|
|
5613
|
+
const allFields = [...getSystemFields()];
|
|
5227
5614
|
if (collection.type === "auth") {
|
|
5228
5615
|
allFields.push(...getAuthSystemFields());
|
|
5229
5616
|
}
|
|
5230
5617
|
allFields.push(...userFields);
|
|
5618
|
+
allFields.push(...getSystemTimestampFields());
|
|
5231
5619
|
lines.push(` "fields": ${generateFieldsArray(allFields, collectionIdMap)},`);
|
|
5232
5620
|
let allIndexes = [...collection.indexes || []];
|
|
5233
5621
|
if (collection.type === "auth") {
|
|
@@ -5257,7 +5645,21 @@ function generateOperationUpMigration(operation, collectionIdMap) {
|
|
|
5257
5645
|
const modification = operation.modifications;
|
|
5258
5646
|
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
|
|
5259
5647
|
let operationCount = 0;
|
|
5260
|
-
const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.
|
|
5648
|
+
const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + (modification.viewQueryUpdate ? 1 : 0) + (modification.permissionsToUpdate.length > 0 ? 1 : modification.rulesToUpdate.length > 0 ? 1 : 0);
|
|
5649
|
+
if (modification.viewQueryUpdate) {
|
|
5650
|
+
operationCount++;
|
|
5651
|
+
const isLast = operationCount === totalOperations;
|
|
5652
|
+
lines.push(
|
|
5653
|
+
generateViewQueryUpdate(
|
|
5654
|
+
collectionName,
|
|
5655
|
+
modification.viewQueryUpdate.newValue,
|
|
5656
|
+
void 0,
|
|
5657
|
+
isLast,
|
|
5658
|
+
collectionIdMap
|
|
5659
|
+
)
|
|
5660
|
+
);
|
|
5661
|
+
if (!isLast) lines.push("");
|
|
5662
|
+
}
|
|
5261
5663
|
for (let i = 0; i < modification.fieldsToAdd.length; i++) {
|
|
5262
5664
|
const field = modification.fieldsToAdd[i];
|
|
5263
5665
|
operationCount++;
|
|
@@ -5297,23 +5699,29 @@ function generateOperationUpMigration(operation, collectionIdMap) {
|
|
|
5297
5699
|
if (!isLast) lines.push("");
|
|
5298
5700
|
}
|
|
5299
5701
|
if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
|
|
5300
|
-
|
|
5301
|
-
|
|
5702
|
+
operationCount++;
|
|
5703
|
+
const isLast = operationCount === totalOperations;
|
|
5704
|
+
if (modification.permissionsToUpdate.length >= 2) {
|
|
5705
|
+
const entries = modification.permissionsToUpdate.map((p) => ({ ruleType: p.ruleType, value: p.newValue }));
|
|
5706
|
+
lines.push(generateGroupedRuleUpdates(collectionName, entries, "rules", isLast, collectionIdMap));
|
|
5707
|
+
} else {
|
|
5708
|
+
const permission = modification.permissionsToUpdate[0];
|
|
5302
5709
|
const varName = `collection_${collectionName}_perm_${permission.ruleType}`;
|
|
5303
|
-
|
|
5304
|
-
lines.push(
|
|
5305
|
-
generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, isLast, collectionIdMap)
|
|
5306
|
-
);
|
|
5307
|
-
if (!isLast) lines.push("");
|
|
5710
|
+
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, isLast, collectionIdMap));
|
|
5308
5711
|
}
|
|
5712
|
+
if (!isLast) lines.push("");
|
|
5309
5713
|
} else if (modification.rulesToUpdate.length > 0) {
|
|
5310
|
-
|
|
5311
|
-
|
|
5714
|
+
operationCount++;
|
|
5715
|
+
const isLast = operationCount === totalOperations;
|
|
5716
|
+
if (modification.rulesToUpdate.length >= 2) {
|
|
5717
|
+
const entries = modification.rulesToUpdate.map((r) => ({ ruleType: r.ruleType, value: r.newValue }));
|
|
5718
|
+
lines.push(generateGroupedRuleUpdates(collectionName, entries, "rules", isLast, collectionIdMap));
|
|
5719
|
+
} else {
|
|
5720
|
+
const rule = modification.rulesToUpdate[0];
|
|
5312
5721
|
const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
|
|
5313
|
-
const isLast = operationCount === totalOperations;
|
|
5314
5722
|
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName, isLast, collectionIdMap));
|
|
5315
|
-
if (!isLast) lines.push("");
|
|
5316
5723
|
}
|
|
5724
|
+
if (!isLast) lines.push("");
|
|
5317
5725
|
}
|
|
5318
5726
|
} else if (operation.type === "delete") {
|
|
5319
5727
|
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection.name;
|
|
@@ -5352,25 +5760,45 @@ function generateOperationDownMigration(operation, collectionIdMap) {
|
|
|
5352
5760
|
const modification = operation.modifications;
|
|
5353
5761
|
const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
|
|
5354
5762
|
let operationCount = 0;
|
|
5355
|
-
const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.
|
|
5763
|
+
const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + (modification.viewQueryUpdate ? 1 : 0) + (modification.permissionsToUpdate.length > 0 ? 1 : modification.rulesToUpdate.length > 0 ? 1 : 0);
|
|
5764
|
+
if (modification.viewQueryUpdate) {
|
|
5765
|
+
operationCount++;
|
|
5766
|
+
const isLast = operationCount === totalOperations;
|
|
5767
|
+
lines.push(
|
|
5768
|
+
generateViewQueryUpdate(
|
|
5769
|
+
collectionName,
|
|
5770
|
+
modification.viewQueryUpdate.oldValue ?? "",
|
|
5771
|
+
`collection_${collectionName}_revert_viewQuery`,
|
|
5772
|
+
isLast,
|
|
5773
|
+
collectionIdMap
|
|
5774
|
+
)
|
|
5775
|
+
);
|
|
5776
|
+
if (!isLast) lines.push("");
|
|
5777
|
+
}
|
|
5356
5778
|
if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
|
|
5357
|
-
|
|
5358
|
-
|
|
5779
|
+
operationCount++;
|
|
5780
|
+
const isLast = operationCount === totalOperations;
|
|
5781
|
+
if (modification.permissionsToUpdate.length >= 2) {
|
|
5782
|
+
const entries = modification.permissionsToUpdate.map((p) => ({ ruleType: p.ruleType, value: p.oldValue }));
|
|
5783
|
+
lines.push(generateGroupedRuleUpdates(collectionName, entries, "revert_rules", isLast, collectionIdMap));
|
|
5784
|
+
} else {
|
|
5785
|
+
const permission = modification.permissionsToUpdate[0];
|
|
5359
5786
|
const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
|
|
5360
|
-
|
|
5361
|
-
lines.push(
|
|
5362
|
-
generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, isLast, collectionIdMap)
|
|
5363
|
-
);
|
|
5364
|
-
if (!isLast) lines.push("");
|
|
5787
|
+
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, isLast, collectionIdMap));
|
|
5365
5788
|
}
|
|
5789
|
+
if (!isLast) lines.push("");
|
|
5366
5790
|
} else if (modification.rulesToUpdate.length > 0) {
|
|
5367
|
-
|
|
5368
|
-
|
|
5791
|
+
operationCount++;
|
|
5792
|
+
const isLast = operationCount === totalOperations;
|
|
5793
|
+
if (modification.rulesToUpdate.length >= 2) {
|
|
5794
|
+
const entries = modification.rulesToUpdate.map((r) => ({ ruleType: r.ruleType, value: r.oldValue }));
|
|
5795
|
+
lines.push(generateGroupedRuleUpdates(collectionName, entries, "revert_rules", isLast, collectionIdMap));
|
|
5796
|
+
} else {
|
|
5797
|
+
const rule = modification.rulesToUpdate[0];
|
|
5369
5798
|
const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
|
|
5370
|
-
const isLast = operationCount === totalOperations;
|
|
5371
5799
|
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName, isLast, collectionIdMap));
|
|
5372
|
-
if (!isLast) lines.push("");
|
|
5373
5800
|
}
|
|
5801
|
+
if (!isLast) lines.push("");
|
|
5374
5802
|
}
|
|
5375
5803
|
for (let i = 0; i < modification.indexesToRemove.length; i++) {
|
|
5376
5804
|
operationCount++;
|
|
@@ -5477,6 +5905,19 @@ function generateUpMigration(diff) {
|
|
|
5477
5905
|
lines.push(` // Modify existing collections`);
|
|
5478
5906
|
for (const modification of diff.collectionsToModify) {
|
|
5479
5907
|
const collectionName = modification.collection;
|
|
5908
|
+
if (modification.viewQueryUpdate) {
|
|
5909
|
+
lines.push(` // Update the view query of ${collectionName}`);
|
|
5910
|
+
lines.push(
|
|
5911
|
+
generateViewQueryUpdate(
|
|
5912
|
+
collectionName,
|
|
5913
|
+
modification.viewQueryUpdate.newValue,
|
|
5914
|
+
void 0,
|
|
5915
|
+
false,
|
|
5916
|
+
collectionIdMap
|
|
5917
|
+
)
|
|
5918
|
+
);
|
|
5919
|
+
lines.push(``);
|
|
5920
|
+
}
|
|
5480
5921
|
if (modification.fieldsToAdd.length > 0) {
|
|
5481
5922
|
lines.push(` // Add fields to ${collectionName}`);
|
|
5482
5923
|
for (let i = 0; i < modification.fieldsToAdd.length; i++) {
|
|
@@ -5522,20 +5963,26 @@ function generateUpMigration(diff) {
|
|
|
5522
5963
|
}
|
|
5523
5964
|
if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
|
|
5524
5965
|
lines.push(` // Update permissions for ${collectionName}`);
|
|
5525
|
-
|
|
5966
|
+
if (modification.permissionsToUpdate.length >= 2) {
|
|
5967
|
+
const entries = modification.permissionsToUpdate.map((p) => ({ ruleType: p.ruleType, value: p.newValue }));
|
|
5968
|
+
lines.push(generateGroupedRuleUpdates(collectionName, entries, "rules", false, collectionIdMap));
|
|
5969
|
+
} else {
|
|
5970
|
+
const permission = modification.permissionsToUpdate[0];
|
|
5526
5971
|
const varName = `collection_${collectionName}_perm_${permission.ruleType}`;
|
|
5527
|
-
lines.push(
|
|
5528
|
-
generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, false, collectionIdMap)
|
|
5529
|
-
);
|
|
5530
|
-
lines.push(``);
|
|
5972
|
+
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, false, collectionIdMap));
|
|
5531
5973
|
}
|
|
5974
|
+
lines.push(``);
|
|
5532
5975
|
} else if (modification.rulesToUpdate.length > 0) {
|
|
5533
5976
|
lines.push(` // Update rules for ${collectionName}`);
|
|
5534
|
-
|
|
5977
|
+
if (modification.rulesToUpdate.length >= 2) {
|
|
5978
|
+
const entries = modification.rulesToUpdate.map((r) => ({ ruleType: r.ruleType, value: r.newValue }));
|
|
5979
|
+
lines.push(generateGroupedRuleUpdates(collectionName, entries, "rules", false, collectionIdMap));
|
|
5980
|
+
} else {
|
|
5981
|
+
const rule = modification.rulesToUpdate[0];
|
|
5535
5982
|
const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
|
|
5536
5983
|
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName, false, collectionIdMap));
|
|
5537
|
-
lines.push(``);
|
|
5538
5984
|
}
|
|
5985
|
+
lines.push(``);
|
|
5539
5986
|
}
|
|
5540
5987
|
}
|
|
5541
5988
|
}
|
|
@@ -5607,22 +6054,41 @@ function generateDownMigration(diff) {
|
|
|
5607
6054
|
lines.push(` // Revert modifications`);
|
|
5608
6055
|
for (const modification of diff.collectionsToModify) {
|
|
5609
6056
|
const collectionName = modification.collection;
|
|
6057
|
+
if (modification.viewQueryUpdate) {
|
|
6058
|
+
lines.push(` // Restore the view query of ${collectionName}`);
|
|
6059
|
+
lines.push(
|
|
6060
|
+
generateViewQueryUpdate(
|
|
6061
|
+
collectionName,
|
|
6062
|
+
modification.viewQueryUpdate.oldValue ?? "",
|
|
6063
|
+
`collection_${collectionName}_revert_viewQuery`,
|
|
6064
|
+
false,
|
|
6065
|
+
collectionIdMap
|
|
6066
|
+
)
|
|
6067
|
+
);
|
|
6068
|
+
lines.push(``);
|
|
6069
|
+
}
|
|
5610
6070
|
if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
|
|
5611
6071
|
lines.push(` // Revert permissions for ${collectionName}`);
|
|
5612
|
-
|
|
6072
|
+
if (modification.permissionsToUpdate.length >= 2) {
|
|
6073
|
+
const entries = modification.permissionsToUpdate.map((p) => ({ ruleType: p.ruleType, value: p.oldValue }));
|
|
6074
|
+
lines.push(generateGroupedRuleUpdates(collectionName, entries, "revert_rules", false, collectionIdMap));
|
|
6075
|
+
} else {
|
|
6076
|
+
const permission = modification.permissionsToUpdate[0];
|
|
5613
6077
|
const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
|
|
5614
|
-
lines.push(
|
|
5615
|
-
generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, false, collectionIdMap)
|
|
5616
|
-
);
|
|
5617
|
-
lines.push(``);
|
|
6078
|
+
lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, false, collectionIdMap));
|
|
5618
6079
|
}
|
|
6080
|
+
lines.push(``);
|
|
5619
6081
|
} else if (modification.rulesToUpdate.length > 0) {
|
|
5620
6082
|
lines.push(` // Revert rules for ${collectionName}`);
|
|
5621
|
-
|
|
6083
|
+
if (modification.rulesToUpdate.length >= 2) {
|
|
6084
|
+
const entries = modification.rulesToUpdate.map((r) => ({ ruleType: r.ruleType, value: r.oldValue }));
|
|
6085
|
+
lines.push(generateGroupedRuleUpdates(collectionName, entries, "revert_rules", false, collectionIdMap));
|
|
6086
|
+
} else {
|
|
6087
|
+
const rule = modification.rulesToUpdate[0];
|
|
5622
6088
|
const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
|
|
5623
6089
|
lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName, false, collectionIdMap));
|
|
5624
|
-
lines.push(``);
|
|
5625
6090
|
}
|
|
6091
|
+
lines.push(``);
|
|
5626
6092
|
}
|
|
5627
6093
|
if (modification.indexesToRemove.length > 0) {
|
|
5628
6094
|
lines.push(` // Restore indexes to ${collectionName}`);
|
|
@@ -5952,6 +6418,9 @@ var MigrationGenerator = class {
|
|
|
5952
6418
|
function detectCollectionDeletions(diff) {
|
|
5953
6419
|
const changes = [];
|
|
5954
6420
|
for (const collection of diff.collectionsToDelete) {
|
|
6421
|
+
if (collection.type === "view") {
|
|
6422
|
+
continue;
|
|
6423
|
+
}
|
|
5955
6424
|
changes.push({
|
|
5956
6425
|
type: "collection_deletion" /* COLLECTION_DELETION */,
|
|
5957
6426
|
description: `Delete collection: ${collection.name}`,
|
|
@@ -6366,7 +6835,11 @@ function formatChangeSummary(diff) {
|
|
|
6366
6835
|
lines.push(chalk__default.default.green.bold(`\u2713 ${totalCollectionsToCreate} collection(s) to create:`));
|
|
6367
6836
|
for (const collection of diff.collectionsToCreate) {
|
|
6368
6837
|
lines.push(chalk__default.default.green(` + ${collection.name} (${collection.type})`));
|
|
6369
|
-
|
|
6838
|
+
if (collection.type === "view") {
|
|
6839
|
+
lines.push(chalk__default.default.gray(` fields derived from the view query`));
|
|
6840
|
+
} else {
|
|
6841
|
+
lines.push(chalk__default.default.gray(` ${collection.fields.length} field(s)`));
|
|
6842
|
+
}
|
|
6370
6843
|
}
|
|
6371
6844
|
lines.push("");
|
|
6372
6845
|
}
|
|
@@ -6411,6 +6884,9 @@ function formatChangeSummary(diff) {
|
|
|
6411
6884
|
if (modification.rulesToUpdate.length > 0) {
|
|
6412
6885
|
lines.push(chalk__default.default.yellow(` ~ ${modification.rulesToUpdate.length} rule(s) to update`));
|
|
6413
6886
|
}
|
|
6887
|
+
if (modification.viewQueryUpdate) {
|
|
6888
|
+
lines.push(chalk__default.default.yellow(` ~ view query to update`));
|
|
6889
|
+
}
|
|
6414
6890
|
lines.push("");
|
|
6415
6891
|
}
|
|
6416
6892
|
}
|
|
@@ -6884,7 +7360,9 @@ exports.convertPocketBaseMigration = convertPocketBaseMigration;
|
|
|
6884
7360
|
exports.convertZodSchemaToCollectionSchema = convertZodSchemaToCollectionSchema;
|
|
6885
7361
|
exports.createMigrationFileStructure = createMigrationFileStructure;
|
|
6886
7362
|
exports.createPermissions = createPermissions;
|
|
7363
|
+
exports.dedentSql = dedentSql;
|
|
6887
7364
|
exports.defineCollection = defineCollection;
|
|
7365
|
+
exports.defineView = defineView;
|
|
6888
7366
|
exports.detectDestructiveChanges = detectDestructiveChanges;
|
|
6889
7367
|
exports.detectDestructiveChangesValidation = detectDestructiveChanges2;
|
|
6890
7368
|
exports.detectFieldChanges = detectFieldChanges;
|
|
@@ -6979,12 +7457,14 @@ exports.saveSnapshot = saveSnapshot;
|
|
|
6979
7457
|
exports.selectSchemaForCollection = selectSchemaForCollection;
|
|
6980
7458
|
exports.singularize = singularize;
|
|
6981
7459
|
exports.snapshotExists = snapshotExists;
|
|
7460
|
+
exports.sql = sql;
|
|
6982
7461
|
exports.summarizeDestructiveChanges = summarizeDestructiveChanges;
|
|
6983
7462
|
exports.toCollectionName = toCollectionName;
|
|
6984
7463
|
exports.unwrapZodType = unwrapZodType;
|
|
6985
7464
|
exports.validatePermissionConfig = validatePermissionConfig;
|
|
6986
7465
|
exports.validateRuleExpression = validateRuleExpression;
|
|
6987
7466
|
exports.validateSnapshot = validateSnapshot;
|
|
7467
|
+
exports.validateViewQuery = validateViewQuery;
|
|
6988
7468
|
exports.withIndexes = withIndexes;
|
|
6989
7469
|
exports.withPermissions = withPermissions;
|
|
6990
7470
|
exports.withProgress = withProgress;
|