@beignet/cli 0.0.8 → 0.0.10
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 +18 -0
- package/README.md +68 -67
- package/dist/choices.d.ts +32 -3
- package/dist/choices.d.ts.map +1 -1
- package/dist/choices.js +54 -3
- package/dist/choices.js.map +1 -1
- package/dist/create-prompts.d.ts +5 -4
- package/dist/create-prompts.d.ts.map +1 -1
- package/dist/create-prompts.js +22 -4
- package/dist/create-prompts.js.map +1 -1
- package/dist/create.d.ts +7 -1
- package/dist/create.d.ts.map +1 -1
- package/dist/create.js +14 -4
- package/dist/create.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -6
- package/dist/index.js.map +1 -1
- package/dist/inspect.js +78 -12
- package/dist/inspect.js.map +1 -1
- package/dist/make.d.ts +21 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +210 -37
- package/dist/make.js.map +1 -1
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +80 -10
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/db/index.d.ts +21 -0
- package/dist/templates/db/index.d.ts.map +1 -0
- package/dist/templates/db/index.js +14 -0
- package/dist/templates/db/index.js.map +1 -0
- package/dist/templates/db/mysql.d.ts +4 -0
- package/dist/templates/db/mysql.d.ts.map +1 -0
- package/dist/templates/db/mysql.js +972 -0
- package/dist/templates/db/mysql.js.map +1 -0
- package/dist/templates/db/postgres.d.ts +4 -0
- package/dist/templates/db/postgres.d.ts.map +1 -0
- package/dist/templates/db/postgres.js +863 -0
- package/dist/templates/db/postgres.js.map +1 -0
- package/dist/templates/db/sqlite.d.ts +3 -0
- package/dist/templates/db/sqlite.d.ts.map +1 -0
- package/dist/templates/db/sqlite.js +878 -0
- package/dist/templates/db/sqlite.js.map +1 -0
- package/dist/templates/db.js +16 -16
- package/dist/templates/index.d.ts +5 -5
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +21 -20
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/server.d.ts +3 -3
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +149 -97
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.d.ts +34 -1
- package/dist/templates/shared.d.ts.map +1 -1
- package/dist/templates/shared.js +45 -0
- package/dist/templates/shared.js.map +1 -1
- package/package.json +2 -2
- package/src/choices.ts +70 -3
- package/src/create-prompts.ts +25 -3
- package/src/create.ts +25 -3
- package/src/index.ts +29 -5
- package/src/inspect.ts +137 -19
- package/src/make.ts +265 -34
- package/src/templates/base.ts +96 -10
- package/src/templates/db/index.ts +34 -0
- package/src/templates/db/mysql.ts +976 -0
- package/src/templates/db/postgres.ts +867 -0
- package/src/templates/{db.ts → db/sqlite.ts} +47 -168
- package/src/templates/index.ts +24 -19
- package/src/templates/server.ts +161 -97
- package/src/templates/shared.ts +90 -1
package/dist/make.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MakeFeatureAddon } from "./choices.js";
|
|
2
|
-
import { type BeignetConfig } from "./config.js";
|
|
2
|
+
import { type BeignetConfig, type ResolvedBeignetConfig } from "./config.js";
|
|
3
3
|
type MakeResourceOptions = {
|
|
4
4
|
name: string;
|
|
5
5
|
cwd?: string;
|
|
@@ -203,6 +203,11 @@ export type MakeScheduleResult = MakeResult;
|
|
|
203
203
|
* Result returned by `beignet make upload`.
|
|
204
204
|
*/
|
|
205
205
|
export type MakeUploadResult = MakeResult;
|
|
206
|
+
/**
|
|
207
|
+
* SQL dialect of the app database. Kept as a local literal union so the
|
|
208
|
+
* generators do not couple to the create-side option types.
|
|
209
|
+
*/
|
|
210
|
+
export type DatabaseName = "sqlite" | "postgres" | "mysql";
|
|
206
211
|
export declare function makeResource(options: MakeResourceOptions): Promise<MakeResourceResult>;
|
|
207
212
|
export declare function makeFeature(options: MakeFeatureOptions): Promise<MakeFeatureResult>;
|
|
208
213
|
export declare function makeContract(options: MakeContractOptions): Promise<MakeContractResult>;
|
|
@@ -220,4 +225,19 @@ export declare function makeNotification(options: MakeNotificationOptions): Prom
|
|
|
220
225
|
export declare function makeListener(options: MakeListenerOptions): Promise<MakeListenerResult>;
|
|
221
226
|
export declare function makeSchedule(options: MakeScheduleOptions): Promise<MakeScheduleResult>;
|
|
222
227
|
export declare function makeUpload(options: MakeUploadOptions): Promise<MakeUploadResult>;
|
|
228
|
+
/**
|
|
229
|
+
* Detect the SQL dialect of a Drizzle app from its generated wiring.
|
|
230
|
+
*
|
|
231
|
+
* Precedence:
|
|
232
|
+
* 1. The provider import in the Drizzle repositories file
|
|
233
|
+
* (`@beignet/provider-db-drizzle/<dialect>`), resolved through the
|
|
234
|
+
* configured infrastructure paths so custom layouts keep working.
|
|
235
|
+
* 2. The provider registration tokens in `server/providers.ts`
|
|
236
|
+
* (`drizzle<Dialect>Provider` / `createDrizzle<Dialect>Provider`).
|
|
237
|
+
* 3. `"sqlite"`, the starter default.
|
|
238
|
+
*
|
|
239
|
+
* Self-healing by design: there is no config field to drift, the detector
|
|
240
|
+
* reads the same files the app boots from.
|
|
241
|
+
*/
|
|
242
|
+
export declare function detectResourceDatabase(targetDir: string, config: ResolvedBeignetConfig): Promise<DatabaseName>;
|
|
223
243
|
//# sourceMappingURL=make.d.ts.map
|
package/dist/make.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"make.d.ts","sourceRoot":"","sources":["../src/make.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"make.d.ts","sourceRoot":"","sources":["../src/make.ts"],"names":[],"mappings":"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"}
|
package/dist/make.js
CHANGED
|
@@ -4,6 +4,41 @@ import path from "node:path";
|
|
|
4
4
|
import { directoryPath, loadBeignetConfig, normalizePath, resolveConfig, } from "./config.js";
|
|
5
5
|
import { appendToArrayExpression, appendToNamedArray, appendToOutboxRegistryArray, arrayInitializerInfo, identifiersFromArrayExpression, insertAfterImports, matchingDelimiterIndex, } from "./registry-edits.js";
|
|
6
6
|
export { makeFeatureAddonChoices } from "./choices.js";
|
|
7
|
+
const drizzleDialects = {
|
|
8
|
+
sqlite: {
|
|
9
|
+
subpath: "sqlite",
|
|
10
|
+
dbTypeName: "DrizzleSqliteDatabase",
|
|
11
|
+
columnModule: "drizzle-orm/sqlite-core",
|
|
12
|
+
tableFunction: "sqliteTable",
|
|
13
|
+
schemaImports: ["integer", "sqliteTable", "text"],
|
|
14
|
+
supportsReturning: true,
|
|
15
|
+
idColumn: (columnName) => `text("${columnName}")`,
|
|
16
|
+
timestampColumn: (columnName) => `text("${columnName}")`,
|
|
17
|
+
integerColumn: (columnName) => `integer("${columnName}")`,
|
|
18
|
+
},
|
|
19
|
+
postgres: {
|
|
20
|
+
subpath: "postgres",
|
|
21
|
+
dbTypeName: "DrizzlePostgresDatabase",
|
|
22
|
+
columnModule: "drizzle-orm/pg-core",
|
|
23
|
+
tableFunction: "pgTable",
|
|
24
|
+
schemaImports: ["integer", "pgTable", "text"],
|
|
25
|
+
supportsReturning: true,
|
|
26
|
+
idColumn: (columnName) => `text("${columnName}")`,
|
|
27
|
+
timestampColumn: (columnName) => `text("${columnName}")`,
|
|
28
|
+
integerColumn: (columnName) => `integer("${columnName}")`,
|
|
29
|
+
},
|
|
30
|
+
mysql: {
|
|
31
|
+
subpath: "mysql",
|
|
32
|
+
dbTypeName: "DrizzleMysqlDatabase",
|
|
33
|
+
columnModule: "drizzle-orm/mysql-core",
|
|
34
|
+
tableFunction: "mysqlTable",
|
|
35
|
+
schemaImports: ["int", "mysqlTable", "text", "varchar"],
|
|
36
|
+
supportsReturning: false,
|
|
37
|
+
idColumn: (columnName) => `varchar("${columnName}", { length: 36 })`,
|
|
38
|
+
timestampColumn: (columnName) => `varchar("${columnName}", { length: 32 })`,
|
|
39
|
+
integerColumn: (columnName) => `int("${columnName}")`,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
7
42
|
export async function makeResource(options) {
|
|
8
43
|
return makeResourceSlice(options, "resource");
|
|
9
44
|
}
|
|
@@ -41,8 +76,11 @@ async function makeResourceSlice(options, mode) {
|
|
|
41
76
|
throw new Error(`beignet make resource expects an app error catalog. Missing ${resourceSharedErrorsPath(config)}.`);
|
|
42
77
|
}
|
|
43
78
|
const persistence = await detectResourcePersistence(targetDir, config);
|
|
79
|
+
const database = persistence === "drizzle"
|
|
80
|
+
? await detectResourceDatabase(targetDir, config)
|
|
81
|
+
: "sqlite";
|
|
44
82
|
const generationOptions = resourceGenerationOptions(options, mode);
|
|
45
|
-
const generatedFiles = resourceFiles(names, config, persistence, mode, generationOptions);
|
|
83
|
+
const generatedFiles = resourceFiles(names, config, persistence, mode, generationOptions, database);
|
|
46
84
|
const plannedFiles = await planGeneratedFiles(targetDir, generatedFiles, {
|
|
47
85
|
force: Boolean(options.force),
|
|
48
86
|
});
|
|
@@ -2590,7 +2628,7 @@ function resourceFiles(names, config, persistence = "memory", mode = "feature",
|
|
|
2590
2628
|
tenant: false,
|
|
2591
2629
|
events: false,
|
|
2592
2630
|
softDelete: false,
|
|
2593
|
-
}) {
|
|
2631
|
+
}, database = "sqlite") {
|
|
2594
2632
|
const useCaseDir = resourceUseCaseDir(names, config);
|
|
2595
2633
|
const infraDir = infrastructureDir(config);
|
|
2596
2634
|
const featureDir = resourceFeatureDir(names, config);
|
|
@@ -2669,12 +2707,13 @@ function resourceFiles(names, config, persistence = "memory", mode = "feature",
|
|
|
2669
2707
|
},
|
|
2670
2708
|
];
|
|
2671
2709
|
if (persistence === "drizzle") {
|
|
2710
|
+
const dialect = drizzleDialects[database];
|
|
2672
2711
|
files.push({
|
|
2673
2712
|
path: drizzleResourceSchemaFilePath(names, config),
|
|
2674
|
-
content: drizzleSchemaFile(names, options),
|
|
2713
|
+
content: drizzleSchemaFile(names, options, dialect),
|
|
2675
2714
|
}, {
|
|
2676
2715
|
path: drizzleResourceRepositoryFilePath(names, config),
|
|
2677
|
-
content: drizzleRepositoryFile(names, config, mode, options),
|
|
2716
|
+
content: drizzleRepositoryFile(names, config, mode, options, dialect),
|
|
2678
2717
|
});
|
|
2679
2718
|
}
|
|
2680
2719
|
return files;
|
|
@@ -2862,6 +2901,37 @@ async function detectResourcePersistence(targetDir, config) {
|
|
|
2862
2901
|
? "drizzle"
|
|
2863
2902
|
: "memory";
|
|
2864
2903
|
}
|
|
2904
|
+
const databaseNames = ["sqlite", "postgres", "mysql"];
|
|
2905
|
+
/**
|
|
2906
|
+
* Detect the SQL dialect of a Drizzle app from its generated wiring.
|
|
2907
|
+
*
|
|
2908
|
+
* Precedence:
|
|
2909
|
+
* 1. The provider import in the Drizzle repositories file
|
|
2910
|
+
* (`@beignet/provider-db-drizzle/<dialect>`), resolved through the
|
|
2911
|
+
* configured infrastructure paths so custom layouts keep working.
|
|
2912
|
+
* 2. The provider registration tokens in `server/providers.ts`
|
|
2913
|
+
* (`drizzle<Dialect>Provider` / `createDrizzle<Dialect>Provider`).
|
|
2914
|
+
* 3. `"sqlite"`, the starter default.
|
|
2915
|
+
*
|
|
2916
|
+
* Self-healing by design: there is no config field to drift, the detector
|
|
2917
|
+
* reads the same files the app boots from.
|
|
2918
|
+
*/
|
|
2919
|
+
export async function detectResourceDatabase(targetDir, config) {
|
|
2920
|
+
const repositories = await readOptionalFile(path.join(targetDir, drizzleRepositoriesPath(config)));
|
|
2921
|
+
const providerImport = repositories?.match(/from\s+["']@beignet\/provider-db-drizzle\/(sqlite|postgres|mysql)["']/);
|
|
2922
|
+
if (providerImport)
|
|
2923
|
+
return providerImport[1];
|
|
2924
|
+
const providers = await readOptionalFile(path.join(targetDir, providersFilePath(config)));
|
|
2925
|
+
if (providers !== undefined) {
|
|
2926
|
+
for (const database of databaseNames) {
|
|
2927
|
+
const dialectPascal = database.charAt(0).toUpperCase() + database.slice(1);
|
|
2928
|
+
const tokens = new RegExp(`\\b(?:drizzle${dialectPascal}Provider|createDrizzle${dialectPascal}Provider)\\b`);
|
|
2929
|
+
if (tokens.test(providers))
|
|
2930
|
+
return database;
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
return "sqlite";
|
|
2934
|
+
}
|
|
2865
2935
|
function resourceFeatureDir(names, config) {
|
|
2866
2936
|
return path.join(config.paths.features, names.pluralKebab);
|
|
2867
2937
|
}
|
|
@@ -3804,16 +3874,16 @@ ${mode === "resource" ? ` async findById(id: string${options.tenant ? ", filter
|
|
|
3804
3874
|
}
|
|
3805
3875
|
`;
|
|
3806
3876
|
}
|
|
3807
|
-
function drizzleSchemaFile(names, options) {
|
|
3808
|
-
return `import {
|
|
3877
|
+
function drizzleSchemaFile(names, options, dialect) {
|
|
3878
|
+
return `import { ${dialect.schemaImports.join(", ")} } from "${dialect.columnModule}";
|
|
3809
3879
|
|
|
3810
|
-
export const ${names.pluralCamel} =
|
|
3811
|
-
id:
|
|
3812
|
-
${options.tenant ? `\ttenantId:
|
|
3813
|
-
version:
|
|
3814
|
-
createdAt:
|
|
3815
|
-
updatedAt:
|
|
3816
|
-
${options.softDelete ? `\tdeletedAt:
|
|
3880
|
+
export const ${names.pluralCamel} = ${dialect.tableFunction}("${names.pluralKebab.replaceAll("-", "_")}", {
|
|
3881
|
+
id: ${dialect.idColumn("id")}.primaryKey(),
|
|
3882
|
+
${options.tenant ? `\ttenantId: ${dialect.idColumn("tenant_id")}.notNull(),\n` : ""} name: text("name").notNull(),
|
|
3883
|
+
version: ${dialect.integerColumn("version")}.notNull(),
|
|
3884
|
+
createdAt: ${dialect.timestampColumn("created_at")}.notNull(),
|
|
3885
|
+
updatedAt: ${dialect.timestampColumn("updated_at")}.notNull(),
|
|
3886
|
+
${options.softDelete ? `\tdeletedAt: ${dialect.timestampColumn("deleted_at")},\n` : ""}});
|
|
3817
3887
|
`;
|
|
3818
3888
|
}
|
|
3819
3889
|
function drizzleResourceWhere(names, options, predicates) {
|
|
@@ -3829,7 +3899,7 @@ function drizzleResourceWhere(names, options, predicates) {
|
|
|
3829
3899
|
return allPredicates[0] ?? "";
|
|
3830
3900
|
return `and(${allPredicates.join(", ")})`;
|
|
3831
3901
|
}
|
|
3832
|
-
function drizzleRepositoryFile(names, config, mode, options) {
|
|
3902
|
+
function drizzleRepositoryFile(names, config, mode, options, dialect) {
|
|
3833
3903
|
const repositoryPortPath = resourcePortFilePath(names, config);
|
|
3834
3904
|
const schemaPath = drizzleSchemaIndexPath(config);
|
|
3835
3905
|
const findWhere = drizzleResourceWhere(names, options, [
|
|
@@ -3863,9 +3933,131 @@ function drizzleRepositoryFile(names, config, mode, options) {
|
|
|
3863
3933
|
"sql",
|
|
3864
3934
|
"type SQL",
|
|
3865
3935
|
].filter((name) => Boolean(name));
|
|
3936
|
+
// After a version-guarded update succeeds, re-select by identity only —
|
|
3937
|
+
// matching what `.returning()` yields on the dialects that support it.
|
|
3938
|
+
const updateReselectWhere = options.tenant
|
|
3939
|
+
? `and(eq(schema.${names.pluralCamel}.id, input.id), eq(schema.${names.pluralCamel}.tenantId, input.tenantId))`
|
|
3940
|
+
: `eq(schema.${names.pluralCamel}.id, input.id)`;
|
|
3941
|
+
// drizzle-orm/mysql2 has no `.returning(...)`; mutations resolve to a
|
|
3942
|
+
// `[ResultSetHeader, FieldPacket[]]` tuple typed as `unknown` through the
|
|
3943
|
+
// generic database seam, so generated MySQL code reads affectedRows
|
|
3944
|
+
// defensively and re-selects rows it needs back.
|
|
3945
|
+
const affectedRowsHelper = mode === "resource" && !dialect.supportsReturning
|
|
3946
|
+
? `
|
|
3947
|
+
// drizzle-orm/mysql2 mutations resolve to [ResultSetHeader, FieldPacket[]],
|
|
3948
|
+
// typed as unknown through the generic database seam, so read affectedRows
|
|
3949
|
+
// defensively.
|
|
3950
|
+
function affectedRows(result: unknown): number {
|
|
3951
|
+
const head: unknown = Array.isArray(result) ? result[0] : undefined;
|
|
3952
|
+
if (head === null || typeof head !== "object") return 0;
|
|
3953
|
+
return "affectedRows" in head && typeof head.affectedRows === "number"
|
|
3954
|
+
? head.affectedRows
|
|
3955
|
+
: 0;
|
|
3956
|
+
}
|
|
3957
|
+
`
|
|
3958
|
+
: "";
|
|
3959
|
+
const createMethod = dialect.supportsReturning
|
|
3960
|
+
? ` async create(input) {
|
|
3961
|
+
const now = new Date().toISOString();
|
|
3962
|
+
const [row] = await db
|
|
3963
|
+
.insert(schema.${names.pluralCamel})
|
|
3964
|
+
.values({
|
|
3965
|
+
id: crypto.randomUUID(),
|
|
3966
|
+
${options.tenant ? `\t\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.name,
|
|
3967
|
+
version: 1,
|
|
3968
|
+
createdAt: now,
|
|
3969
|
+
updatedAt: now,
|
|
3970
|
+
})
|
|
3971
|
+
.returning();
|
|
3972
|
+
|
|
3973
|
+
if (!row) {
|
|
3974
|
+
throw new Error("Failed to create ${names.singularKebab}.");
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3977
|
+
return to${names.singularPascal}(row);
|
|
3978
|
+
},
|
|
3979
|
+
`
|
|
3980
|
+
: ` async create(input) {
|
|
3981
|
+
const now = new Date().toISOString();
|
|
3982
|
+
const ${names.singularCamel}: ${names.singularPascal} = {
|
|
3983
|
+
id: crypto.randomUUID(),
|
|
3984
|
+
${options.tenant ? `\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.name,
|
|
3985
|
+
version: 1,
|
|
3986
|
+
createdAt: now,
|
|
3987
|
+
updatedAt: now,
|
|
3988
|
+
};
|
|
3989
|
+
await db.insert(schema.${names.pluralCamel}).values(${names.singularCamel});
|
|
3990
|
+
|
|
3991
|
+
return ${names.singularCamel};
|
|
3992
|
+
},
|
|
3993
|
+
`;
|
|
3994
|
+
const resourceMethods = mode !== "resource"
|
|
3995
|
+
? ""
|
|
3996
|
+
: dialect.supportsReturning
|
|
3997
|
+
? ` async findById(id: string${options.tenant ? ", filter" : ""}) {
|
|
3998
|
+
const [row] = await db
|
|
3999
|
+
.select()
|
|
4000
|
+
.from(schema.${names.pluralCamel})
|
|
4001
|
+
.where(${findWhere})
|
|
4002
|
+
.limit(1);
|
|
4003
|
+
|
|
4004
|
+
return row ? to${names.singularPascal}(row) : null;
|
|
4005
|
+
},
|
|
4006
|
+
async update(input) {
|
|
4007
|
+
const [row] = await db
|
|
4008
|
+
.update(schema.${names.pluralCamel})
|
|
4009
|
+
.set({
|
|
4010
|
+
name: input.name,
|
|
4011
|
+
version: input.version + 1,
|
|
4012
|
+
updatedAt: new Date().toISOString(),
|
|
4013
|
+
})
|
|
4014
|
+
.where(${updateWhere})
|
|
4015
|
+
.returning();
|
|
4016
|
+
|
|
4017
|
+
return row ? to${names.singularPascal}(row) : null;
|
|
4018
|
+
},
|
|
4019
|
+
async delete(id: string${options.tenant ? ", filter" : ""}) {
|
|
4020
|
+
${options.softDelete ? `\t\t\tconst now = new Date().toISOString();\n\t\t\tconst rows = await db\n\t\t\t\t.update(schema.${names.pluralCamel})\n\t\t\t\t.set({ deletedAt: now, updatedAt: now })\n\t\t\t\t.where(${deleteWhere})\n\t\t\t\t.returning({ id: schema.${names.pluralCamel}.id });\n` : `\t\t\tconst rows = await db\n\t\t\t\t.delete(schema.${names.pluralCamel})\n\t\t\t\t.where(${deleteWhere})\n\t\t\t\t.returning({ id: schema.${names.pluralCamel}.id });\n`}
|
|
4021
|
+
return rows.length > 0;
|
|
4022
|
+
},
|
|
4023
|
+
`
|
|
4024
|
+
: ` async findById(id: string${options.tenant ? ", filter" : ""}) {
|
|
4025
|
+
const [row] = await db
|
|
4026
|
+
.select()
|
|
4027
|
+
.from(schema.${names.pluralCamel})
|
|
4028
|
+
.where(${findWhere})
|
|
4029
|
+
.limit(1);
|
|
4030
|
+
|
|
4031
|
+
return row ? to${names.singularPascal}(row) : null;
|
|
4032
|
+
},
|
|
4033
|
+
async update(input) {
|
|
4034
|
+
const result = await db
|
|
4035
|
+
.update(schema.${names.pluralCamel})
|
|
4036
|
+
.set({
|
|
4037
|
+
name: input.name,
|
|
4038
|
+
version: input.version + 1,
|
|
4039
|
+
updatedAt: new Date().toISOString(),
|
|
4040
|
+
})
|
|
4041
|
+
.where(${updateWhere});
|
|
4042
|
+
|
|
4043
|
+
if (affectedRows(result) === 0) return null;
|
|
4044
|
+
|
|
4045
|
+
const [row] = await db
|
|
4046
|
+
.select()
|
|
4047
|
+
.from(schema.${names.pluralCamel})
|
|
4048
|
+
.where(${updateReselectWhere})
|
|
4049
|
+
.limit(1);
|
|
4050
|
+
|
|
4051
|
+
return row ? to${names.singularPascal}(row) : null;
|
|
4052
|
+
},
|
|
4053
|
+
async delete(id: string${options.tenant ? ", filter" : ""}) {
|
|
4054
|
+
${options.softDelete ? `\t\t\tconst now = new Date().toISOString();\n\t\t\tconst result = await db\n\t\t\t\t.update(schema.${names.pluralCamel})\n\t\t\t\t.set({ deletedAt: now, updatedAt: now })\n\t\t\t\t.where(${deleteWhere});\n` : `\t\t\tconst result = await db\n\t\t\t\t.delete(schema.${names.pluralCamel})\n\t\t\t\t.where(${deleteWhere});\n`}
|
|
4055
|
+
return affectedRows(result) > 0;
|
|
4056
|
+
},
|
|
4057
|
+
`;
|
|
3866
4058
|
return `import type { beignetServerOnly } from "@beignet/core/server-only";
|
|
3867
4059
|
import { cursorPageResult } from "@beignet/core/pagination";
|
|
3868
|
-
import type {
|
|
4060
|
+
import type { ${dialect.dbTypeName} } from "@beignet/provider-db-drizzle/${dialect.subpath}";
|
|
3869
4061
|
import { ${drizzleImports.join(", ")} } from "drizzle-orm";
|
|
3870
4062
|
import type { ${names.singularPascal}Repository } from "${aliasModule(repositoryPortPath)}";
|
|
3871
4063
|
import { encode${names.singularPascal}Cursor } from "${aliasModule(resourceSchemaFilePath(names, config))}";
|
|
@@ -3886,7 +4078,7 @@ ${options.tenant ? `\t\ttenantId: row.tenantId,\n` : ""} name: row.name,
|
|
|
3886
4078
|
updatedAt: row.updatedAt,
|
|
3887
4079
|
};
|
|
3888
4080
|
}
|
|
3889
|
-
|
|
4081
|
+
${affectedRowsHelper}
|
|
3890
4082
|
type List${names.pluralPascal}Query = Parameters<${names.singularPascal}Repository["list"]>[0];
|
|
3891
4083
|
|
|
3892
4084
|
function ${names.singularCamel}SortColumn(query: List${names.pluralPascal}Query) {
|
|
@@ -3945,7 +4137,7 @@ function cursorFor${names.singularPascal}(
|
|
|
3945
4137
|
}
|
|
3946
4138
|
|
|
3947
4139
|
export function createDrizzle${names.singularPascal}Repository(
|
|
3948
|
-
db:
|
|
4140
|
+
db: ${dialect.dbTypeName}<typeof schema>,
|
|
3949
4141
|
): ${names.singularPascal}Repository {
|
|
3950
4142
|
return {
|
|
3951
4143
|
async list(query) {
|
|
@@ -3968,26 +4160,7 @@ export function createDrizzle${names.singularPascal}Repository(
|
|
|
3968
4160
|
nextCursor,
|
|
3969
4161
|
);
|
|
3970
4162
|
},
|
|
3971
|
-
|
|
3972
|
-
const now = new Date().toISOString();
|
|
3973
|
-
const [row] = await db
|
|
3974
|
-
.insert(schema.${names.pluralCamel})
|
|
3975
|
-
.values({
|
|
3976
|
-
id: crypto.randomUUID(),
|
|
3977
|
-
${options.tenant ? `\t\t\t\t\ttenantId: input.tenantId,\n` : ""} name: input.name,
|
|
3978
|
-
version: 1,
|
|
3979
|
-
createdAt: now,
|
|
3980
|
-
updatedAt: now,
|
|
3981
|
-
})
|
|
3982
|
-
.returning();
|
|
3983
|
-
|
|
3984
|
-
if (!row) {
|
|
3985
|
-
throw new Error("Failed to create ${names.singularKebab}.");
|
|
3986
|
-
}
|
|
3987
|
-
|
|
3988
|
-
return to${names.singularPascal}(row);
|
|
3989
|
-
},
|
|
3990
|
-
${mode === "resource" ? ` async findById(id: string${options.tenant ? ", filter" : ""}) {\n const [row] = await db\n .select()\n .from(schema.${names.pluralCamel})\n .where(${findWhere})\n .limit(1);\n\n return row ? to${names.singularPascal}(row) : null;\n },\n async update(input) {\n const [row] = await db\n .update(schema.${names.pluralCamel})\n .set({\n name: input.name,\n version: input.version + 1,\n updatedAt: new Date().toISOString(),\n })\n .where(${updateWhere})\n .returning();\n\n return row ? to${names.singularPascal}(row) : null;\n },\n async delete(id: string${options.tenant ? ", filter" : ""}) {\n${options.softDelete ? `\t\t\tconst now = new Date().toISOString();\n\t\t\tconst rows = await db\n\t\t\t\t.update(schema.${names.pluralCamel})\n\t\t\t\t.set({ deletedAt: now, updatedAt: now })\n\t\t\t\t.where(${deleteWhere})\n\t\t\t\t.returning({ id: schema.${names.pluralCamel}.id });\n` : `\t\t\tconst rows = await db\n\t\t\t\t.delete(schema.${names.pluralCamel})\n\t\t\t\t.where(${deleteWhere})\n\t\t\t\t.returning({ id: schema.${names.pluralCamel}.id });\n`}\n return rows.length > 0;\n },\n` : ""}
|
|
4163
|
+
${createMethod}${resourceMethods}
|
|
3991
4164
|
};
|
|
3992
4165
|
}
|
|
3993
4166
|
`;
|