Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/generators/configurations/initializeRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export const initalizeRoot = (
mkdirSync(projectName);
const srcDir = join(projectName, 'src');
mkdirSync(srcDir);
mkdirSync(join(srcDir, 'types'));
const typesDirectory = join(srcDir, 'types');
mkdirSync(typesDirectory);

const constantsSrc = join(templatesDirectory, 'constants.ts');
const constantsDest = join(srcDir, 'constants.ts');
Expand All @@ -40,5 +41,10 @@ export const initalizeRoot = (
join(projectAssetsDirectory, 'png', 'absolutejs-temp.png')
);

return { backendDirectory, frontendDirectory, projectAssetsDirectory };
return {
backendDirectory,
frontendDirectory,
projectAssetsDirectory,
typesDirectory
};
};
42 changes: 42 additions & 0 deletions src/generators/db/generateDatabaseTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { AuthProvider, DatabaseHost } from '../../types';

type GenerateTypesProps = {
databaseHost: DatabaseHost;
authProvider: AuthProvider;
};

export const generateDatabaseTypes = ({
databaseHost,
authProvider
}: GenerateTypesProps) => {
let dbImport = '';
let dbTypeLine = '';
if (databaseHost === 'neon') {
dbImport = `import { NeonHttpDatabase } from 'drizzle-orm/neon-http';`;
dbTypeLine = 'export type DatabaseType = NeonHttpDatabase<SchemaType>;';
} else if (databaseHost === 'planetscale') {
dbImport = `import { PlanetScaleDatabase } from 'drizzle-orm/planetscale-serverless';`;
dbTypeLine =
'export type DatabaseType = PlanetScaleDatabase<SchemaType>;';
} else if (databaseHost === 'turso') {
dbImport = `import { LibSQLDatabase } from 'drizzle-orm/libsql';`;
dbTypeLine = 'export type DatabaseType = LibSQLDatabase<SchemaType>;';
}
Comment on lines +12 to +24
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add handling for unhandled databaseHost values.

The function only handles 'neon', 'planetscale', and 'turso' as databaseHost values, but according to the type definition, databaseHost can also be undefined or 'none'. When an unhandled value is provided, dbImport and dbTypeLine remain empty strings, resulting in a generated file without a DatabaseType export. This will cause TypeScript compilation errors if downstream code imports or references DatabaseType.

Consider one of the following approaches:

  1. Add validation to prevent calling this function with unsupported databaseHost values
  2. Add a default case that throws an error for unsupported values
  3. Return early or skip file generation for non-hosted database scenarios

Apply this diff to add validation:

 export const generateDatabaseTypes = ({
 	databaseHost,
 	authProvider
 }: GenerateTypesProps) => {
+	// Skip type generation for non-hosted databases
+	if (!databaseHost || databaseHost === 'none') {
+		return null;
+	}
+
 	let dbImport = '';
 	let dbTypeLine = '';
 	if (databaseHost === 'neon') {
 		dbImport = `import { NeonHttpDatabase } from 'drizzle-orm/neon-http';`;
 		dbTypeLine = 'export type DatabaseType = NeonHttpDatabase<SchemaType>;';
 	} else if (databaseHost === 'planetscale') {
 		dbImport = `import { PlanetScaleDatabase } from 'drizzle-orm/planetscale-serverless';`;
 		dbTypeLine =
 			'export type DatabaseType = PlanetScaleDatabase<SchemaType>;';
 	} else if (databaseHost === 'turso') {
 		dbImport = `import { LibSQLDatabase } from 'drizzle-orm/libsql';`;
 		dbTypeLine = 'export type DatabaseType = LibSQLDatabase<SchemaType>;';
+	} else {
+		throw new Error(`Unsupported databaseHost: ${databaseHost}`);
 	}

Then update the caller in scaffoldDatabase.ts to handle the null return:

const drizzleTypes = generateDatabaseTypes({
	authProvider,
	databaseHost
});
if (drizzleTypes !== null) {
	writeFileSync(join(typesDirectory, 'databaseTypes.ts'), drizzleTypes);
}


const schemaImport =
authProvider === 'absoluteAuth'
? `import { users, SchemaType } from '../../db/schema';`
: `import { countHistory, SchemaType } from '../../db/schema';`;
const extraTypes =
authProvider === 'absoluteAuth'
? `export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;`
: `export type CountHistory = typeof countHistory.$inferSelect;
export type NewCountHistory = typeof countHistory.$inferInsert;`;

return `${schemaImport}
${dbImport}

${dbTypeLine ? `${dbTypeLine}\n\n` : '\n'}${extraTypes}
`;
};
30 changes: 1 addition & 29 deletions src/generators/db/generateDrizzleSchema.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
AuthProvider,
AvailableDrizzleDialect,
DatabaseHost
} from '../../types';
import { AuthProvider, AvailableDrizzleDialect } from '../../types';

const DIALECTS = {
gel: {
Expand Down Expand Up @@ -57,15 +53,13 @@ const DIALECTS = {

type GenerateSchemaProps = {
databaseEngine: AvailableDrizzleDialect;
databaseHost: DatabaseHost;
authProvider: AuthProvider;
};

const builder = (expr: string) => expr.split('(')[0];

export const generateDrizzleSchema = ({
databaseEngine,
databaseHost,
authProvider
}: GenerateSchemaProps) => {
const cfg = DIALECTS[databaseEngine];
Expand All @@ -91,20 +85,6 @@ export const generateDrizzleSchema = ({
? `import { sql } from 'drizzle-orm';\n`
: '';

let dbImport = '';
let dbTypeLine = '';
if (databaseHost === 'neon') {
dbImport = `import { NeonHttpDatabase } from 'drizzle-orm/neon-http';`;
dbTypeLine = 'export type DatabaseType = NeonHttpDatabase<SchemaType>;';
} else if (databaseHost === 'planetscale') {
dbImport = `import { PlanetScaleDatabase } from 'drizzle-orm/planetscale-serverless';`;
dbTypeLine =
'export type DatabaseType = PlanetScaleDatabase<SchemaType>;';
} else if (databaseHost === 'turso') {
dbImport = `import { LibSQLDatabase } from 'drizzle-orm/libsql';`;
dbTypeLine = 'export type DatabaseType = LibSQLDatabase<SchemaType>;';
}

let uidColumn: string;
if (databaseEngine === 'mysql' || databaseEngine === 'singlestore' || databaseEngine === 'mariadb') {
uidColumn = `${intBuilder}('uid').primaryKey().autoincrement()`;
Expand Down Expand Up @@ -140,16 +120,9 @@ const MILLIS_PER_DAY = 86400000;\n\n`

const schemaKey =
authProvider === 'absoluteAuth' ? 'users' : 'countHistory';
const extraTypes =
authProvider === 'absoluteAuth'
? `export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;`
: `export type CountHistory = typeof countHistory.$inferSelect;
export type NewCountHistory = typeof countHistory.$inferInsert;`;

return `
${sqliteImports}${builderImport}
${dbImport}

${constsBlock}${tableBlock}

Expand All @@ -158,6 +131,5 @@ export const schema = {
};

export type SchemaType = typeof schema;
${dbTypeLine ? `${dbTypeLine}\n\n` : '\n'}${extraTypes}
`;
};
14 changes: 11 additions & 3 deletions src/generators/db/scaffoldDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { isDrizzleDialect } from '../../typeGuards';
import type { CreateConfiguration } from '../../types';
import { checkSqliteInstalled } from '../../utils/checkSqliteInstalled';
import { createDrizzleConfig } from '../configurations/generateDrizzleConfig';
import { generateDatabaseTypes } from './generateDatabaseTypes';
import { generateDrizzleSchema } from './generateDrizzleSchema';
import { generateDBHandlers } from './generateHandlers';
import { generateSqliteSchema } from './generateSqliteSchema';
Expand All @@ -22,6 +23,7 @@ type ScaffoldDatabaseProps = Pick<
> & {
databaseDirectory: string;
backendDirectory: string;
typesDirectory: string;
};

export const scaffoldDatabase = async ({
Expand All @@ -31,7 +33,8 @@ export const scaffoldDatabase = async ({
databaseDirectory,
backendDirectory,
authProvider,
orm
orm,
typesDirectory
}: ScaffoldDatabaseProps) => {
const projectDatabaseDirectory = join(projectName, databaseDirectory);
const handlerDirectory = join(backendDirectory, 'handlers');
Expand Down Expand Up @@ -87,15 +90,20 @@ export const scaffoldDatabase = async ({

const drizzleSchema = generateDrizzleSchema({
authProvider,
databaseEngine,
databaseHost
databaseEngine
});
writeFileSync(
join(projectDatabaseDirectory, 'schema.ts'),
drizzleSchema
);
createDrizzleConfig({ databaseDirectory, databaseEngine, projectName });

const drizzleTypes = generateDatabaseTypes({
authProvider,
databaseHost
});
writeFileSync(join(typesDirectory, 'databaseTypes.ts'), drizzleTypes);

return;
}

Expand Down
6 changes: 3 additions & 3 deletions src/generators/project/generateImportsBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ export const generateImportsBlock = ({
...(databaseEngine === 'sqlite' && !isRemoteHost
? []
: [`import { getEnv } from '@absolutejs/absolute'`]),
authProvider === 'absoluteAuth'
? `import { schema, User } from '../../db/schema'`
: `import { schema } from '../../db/schema'`
...(authProvider === 'absoluteAuth'
? [`import { schema } from '../../db/schema'`, `import { User } from '../types/databaseTypes'`]
: [`import { schema } from '../../db/schema'`])
Comment on lines +162 to +164
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the import path and User type availability.

The User type import has been moved from '../../db/schema' to '../types/databaseTypes'. Ensure that:

  1. The relative path '../types/databaseTypes' correctly resolves to the new typesDirectory location from the generated backend file
  2. The User type is properly exported from the generated databaseTypes.ts file

Run the following script to verify the import path and type availability:


🏁 Script executed:

#!/bin/bash
# Description: Verify the User type is exported from the new databaseTypes file and check path consistency

# Find where generateDatabaseTypes creates the types file
echo "=== Checking generateDatabaseTypes implementation ==="
ast-grep --pattern 'export $_ generateDatabaseTypes($$$) {
  $$$
}'

# Search for User type exports in database type generation
echo -e "\n=== Searching for User type exports ==="
rg -nP --type=ts 'export\s+(type|interface)\s+User\b' -C 3

# Check where the imports are being written relative to backend directory
echo -e "\n=== Checking typesDirectory usage in scaffolding ==="
rg -nP --type=ts 'typesDirectory' -C 2

# Verify the generated imports structure
echo -e "\n=== Checking other usages of schema imports ==="
rg -nP --type=ts "from ['\"].*db/schema['\"]" -C 1

Length of output: 5506


Fix relative import path for User type.

The User type is correctly exported from the generated databaseTypes.ts file, but the relative import path is incorrect. The path should be '../../types/databaseTypes' (not '../types/databaseTypes') to correctly resolve from the generated backend file location to src/types/databaseTypes.ts.

Update line 163 in src/generators/project/generateImportsBlock.ts:

? [`import { schema } from '../../db/schema'`, `import { User } from '../../types/databaseTypes'`]
🤖 Prompt for AI Agents
In src/generators/project/generateImportsBlock.ts around lines 162 to 164, the
relative import for the User type is wrong; change the second import path from
'../types/databaseTypes' to '../../types/databaseTypes' so the generated backend
file correctly resolves src/types/databaseTypes.ts. Update the array returned
when authProvider === 'absoluteAuth' to use `import { User } from
'../../types/databaseTypes'` while keeping the schema import as-is.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path is correct as the import is in src/backend/server.ts and the types file is in src/types/databaseTypes.ts

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bnziv, you're absolutely right! I apologize for the confusion.

From src/backend/server.ts to src/types/databaseTypes.ts, the relative path '../types/databaseTypes' is indeed correct:

  • ../ goes up from backend/ to src/
  • types/databaseTypes then navigates into the types directory

The import path as written in the code is accurate. Thank you for the clarification!

);
}

Expand Down
11 changes: 8 additions & 3 deletions src/scaffold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,12 @@ export const scaffold = async ({
const __dirname = dirname(fileURLToPath(import.meta.url));
const templatesDirectory = join(__dirname, '/templates');

const { frontendDirectory, backendDirectory, projectAssetsDirectory } =
initalizeRoot(projectName, templatesDirectory);
const {
frontendDirectory,
backendDirectory,
projectAssetsDirectory,
typesDirectory
} = initalizeRoot(projectName, templatesDirectory);

copyFileSync(
join(templatesDirectory, 'README.md'),
Expand Down Expand Up @@ -103,7 +107,8 @@ export const scaffold = async ({
databaseEngine,
databaseHost,
orm,
projectName
projectName,
typesDirectory
}))
);

Expand Down