@rebasepro/server-postgresql 0.0.1-canary.09e5ec5 → 0.0.1-canary.3263433
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/dist/index.es.js +171 -180
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +171 -180
- package/dist/index.umd.js.map +1 -1
- package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +6 -0
- package/dist/types/src/controllers/auth.d.ts +2 -2
- package/dist/types/src/controllers/collection_registry.d.ts +2 -1
- package/dist/types/src/controllers/data_driver.d.ts +36 -1
- package/dist/types/src/types/backend_hooks.d.ts +187 -0
- package/dist/types/src/types/collections.d.ts +11 -10
- package/dist/types/src/types/cron.d.ts +1 -1
- package/dist/types/src/types/entity_views.d.ts +4 -6
- package/dist/types/src/types/formex.d.ts +40 -0
- package/dist/types/src/types/index.d.ts +2 -0
- package/dist/types/src/types/plugins.d.ts +6 -3
- package/dist/types/src/types/properties.d.ts +61 -89
- package/dist/types/src/types/slots.d.ts +20 -10
- package/dist/types/src/types/translations.d.ts +4 -0
- package/package.json +6 -5
- package/src/PostgresBackendDriver.ts +9 -0
- package/src/cli.ts +1 -1
- package/src/schema/generate-drizzle-schema-logic.ts +7 -25
- package/src/schema/introspect-db-logic.ts +61 -11
- package/src/services/EntityPersistService.ts +7 -1
- package/test/generate-drizzle-schema.test.ts +47 -0
- package/test/introspect-db-generation.test.ts +1 -1
- package/test/introspect-db-utils.test.ts +18 -15
- package/test/relations.test.ts +4 -4
|
@@ -666,6 +666,53 @@ using: "{is_locked} = false" }
|
|
|
666
666
|
expect(result).toContain('as: "restrictive"');
|
|
667
667
|
});
|
|
668
668
|
|
|
669
|
+
it("should enable RLS on every table even without any security rules", async () => {
|
|
670
|
+
const collections: EntityCollection[] = [{
|
|
671
|
+
slug: "public_data",
|
|
672
|
+
table: "public_data",
|
|
673
|
+
name: "Public Data",
|
|
674
|
+
properties: { title: { type: "string" } }
|
|
675
|
+
// No securityRules defined — table should still have .enableRLS()
|
|
676
|
+
}];
|
|
677
|
+
|
|
678
|
+
const result = await generateSchema(collections);
|
|
679
|
+
expect(result).toContain(".enableRLS()");
|
|
680
|
+
// No policies should be generated
|
|
681
|
+
expect(result).not.toContain("pgPolicy(");
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
it("should enable RLS on tables that do have security rules", async () => {
|
|
685
|
+
const collections: EntityCollection[] = [{
|
|
686
|
+
slug: "secure_data",
|
|
687
|
+
table: "secure_data",
|
|
688
|
+
name: "Secure Data",
|
|
689
|
+
properties: { title: { type: "string" } },
|
|
690
|
+
securityRules: [
|
|
691
|
+
{ operation: "select", access: "public" }
|
|
692
|
+
]
|
|
693
|
+
}];
|
|
694
|
+
|
|
695
|
+
const result = await generateSchema(collections);
|
|
696
|
+
expect(result).toContain(".enableRLS()");
|
|
697
|
+
expect(result).toContain("pgPolicy(");
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
it("should fall back to deny-all (sql`false`) when no USING clause can be generated", async () => {
|
|
701
|
+
const collections: EntityCollection[] = [{
|
|
702
|
+
slug: "deny_test",
|
|
703
|
+
table: "deny_test",
|
|
704
|
+
name: "Deny Test",
|
|
705
|
+
properties: { title: { type: "string" } },
|
|
706
|
+
securityRules: [
|
|
707
|
+
{ operation: "select" }
|
|
708
|
+
// No access, ownerField, or using — should produce sql`false`
|
|
709
|
+
]
|
|
710
|
+
}];
|
|
711
|
+
|
|
712
|
+
const result = await generateSchema(collections);
|
|
713
|
+
expect(result).toContain("sql`false`");
|
|
714
|
+
});
|
|
715
|
+
|
|
669
716
|
});
|
|
670
717
|
});
|
|
671
718
|
// V2 improvements tests
|
|
@@ -49,7 +49,7 @@ describe("generateCollectionFile", () => {
|
|
|
49
49
|
expect(result).toContain('type: "number"');
|
|
50
50
|
expect(result).toContain('type: "boolean"');
|
|
51
51
|
expect(result).toContain('type: "date"');
|
|
52
|
-
expect(result).toContain('type: "
|
|
52
|
+
expect(result).toContain('type: "map"');
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
it("skips FK columns from properties (they become relations)", () => {
|
|
@@ -190,14 +190,14 @@ describe("mapPgType", () => {
|
|
|
190
190
|
expect(mapPgType(t)).toBe("date");
|
|
191
191
|
}
|
|
192
192
|
});
|
|
193
|
-
it("maps JSON types to
|
|
194
|
-
expect(mapPgType("json")).toBe("
|
|
195
|
-
expect(mapPgType("jsonb")).toBe("
|
|
193
|
+
it("maps JSON types to map", () => {
|
|
194
|
+
expect(mapPgType("json")).toBe("map");
|
|
195
|
+
expect(mapPgType("jsonb")).toBe("map");
|
|
196
196
|
});
|
|
197
|
-
it("maps ARRAY and underscore-prefixed types to
|
|
198
|
-
expect(mapPgType("ARRAY")).toBe("
|
|
199
|
-
expect(mapPgType("_int4")).toBe("
|
|
200
|
-
expect(mapPgType("_text")).toBe("
|
|
197
|
+
it("maps ARRAY and underscore-prefixed types to array", () => {
|
|
198
|
+
expect(mapPgType("ARRAY")).toBe("array");
|
|
199
|
+
expect(mapPgType("_int4")).toBe("array");
|
|
200
|
+
expect(mapPgType("_text")).toBe("array");
|
|
201
201
|
});
|
|
202
202
|
it("maps string-like types to string", () => {
|
|
203
203
|
for (const t of ["text", "varchar", "character varying", "char", "character", "uuid", "bytea", "inet", "cidr", "macaddr", "macaddr8", "interval"]) {
|
|
@@ -350,9 +350,12 @@ describe("generateIndexContent", () => {
|
|
|
350
350
|
expect(lines[2]).toContain("zebra");
|
|
351
351
|
});
|
|
352
352
|
|
|
353
|
-
it("
|
|
353
|
+
it("generates import statements and collections array", () => {
|
|
354
354
|
const result = generateIndexContent(["users"]);
|
|
355
|
-
expect(result).
|
|
355
|
+
expect(result).toContain('import usersCollection from "./users";');
|
|
356
|
+
expect(result).toContain('export const collections = [');
|
|
357
|
+
expect(result).toContain(' usersCollection,');
|
|
358
|
+
expect(result).toContain('];');
|
|
356
359
|
});
|
|
357
360
|
});
|
|
358
361
|
|
|
@@ -361,16 +364,16 @@ describe("generateIndexContent", () => {
|
|
|
361
364
|
// ═══════════════════════════════════════════════════════════════════════
|
|
362
365
|
describe("mergeIndexContent", () => {
|
|
363
366
|
it("adds new exports without duplicating existing ones", () => {
|
|
364
|
-
const existing = '
|
|
367
|
+
const existing = 'import usersCollection from "./users";\n\nexport const collections = [\n usersCollection,\n];\n';
|
|
365
368
|
const result = mergeIndexContent(existing, ["users", "posts"]);
|
|
366
|
-
expect(result.match(/users
|
|
367
|
-
expect(result).toContain('
|
|
368
|
-
|
|
369
|
-
expect(result
|
|
369
|
+
expect(result.match(/import usersCollection from ".\/users";/g)!.length).toBe(1);
|
|
370
|
+
expect(result).toContain('import postsCollection from "./posts";');
|
|
371
|
+
expect(result).toContain('usersCollection,');
|
|
372
|
+
expect(result).toContain('postsCollection,');
|
|
370
373
|
});
|
|
371
374
|
|
|
372
375
|
it("returns existing content trimmed + newline when no new files", () => {
|
|
373
|
-
const existing = '
|
|
376
|
+
const existing = 'import aCollection from "./a";\n\nexport const collections = [\n aCollection,\n];\n';
|
|
374
377
|
const result = mergeIndexContent(existing, ["a"]);
|
|
375
378
|
expect(result.trim()).toBe(existing.trim());
|
|
376
379
|
});
|
package/test/relations.test.ts
CHANGED
|
@@ -382,8 +382,8 @@ relationName: "author" }
|
|
|
382
382
|
// Should create owning relation on profiles
|
|
383
383
|
expect(cleanResult).toContain("export const profilesRelations = drizzleRelations(profiles, ({ one, many }) => ({ \"author\": one(authors, { fields: [profiles.author_id], references: [authors.id], relationName: \"profiles_author_id\" }) }));");
|
|
384
384
|
|
|
385
|
-
// Should create inverse relation on authors
|
|
386
|
-
expect(cleanResult).toContain("export const authorsRelations = drizzleRelations(authors, ({ one, many }) => ({ \"profile\": one(profiles, {
|
|
385
|
+
// Should create inverse relation on authors — inverse side has NO fields/references
|
|
386
|
+
expect(cleanResult).toContain("export const authorsRelations = drizzleRelations(authors, ({ one, many }) => ({ \"profile\": one(profiles, { relationName: \"profiles_author_id\" }) }));");
|
|
387
387
|
});
|
|
388
388
|
|
|
389
389
|
it("should generate owning one-to-many relations", async () => {
|
|
@@ -818,9 +818,9 @@ relationName: "user" }
|
|
|
818
818
|
`"user": one(users, { fields: [profiles.user_id], references: [users.id], relationName: \"${expectedSharedName}\" })`
|
|
819
819
|
);
|
|
820
820
|
|
|
821
|
-
// Inverse side (users → profiles)
|
|
821
|
+
// Inverse side (users → profiles) — no fields/references, paired by relationName only
|
|
822
822
|
expect(cleanResult).toContain(
|
|
823
|
-
`"profile": one(profiles, {
|
|
823
|
+
`"profile": one(profiles, { relationName: \"${expectedSharedName}\" })`
|
|
824
824
|
);
|
|
825
825
|
|
|
826
826
|
// Both must match
|