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
3 changes: 2 additions & 1 deletion src/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const availableDrizzleDialects = [
'mysql',
'postgresql',
'sqlite',
'singlestore'
'singlestore',
'mariadb'
] as const;

export const availablePrismaDialects = [
Expand Down
4 changes: 2 additions & 2 deletions src/generators/configurations/generateEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ type GenerateEnvProps = Pick<
const databaseURLS = {
cockroachdb: 'cockroachdb://user:password@localhost:26257/database',
gel: 'gel://user:password@localhost:5432/database',
mariadb: 'mariadb://user:password@localhost:3306/database',
mariadb: 'mariadb://user:userpassword@localhost:3306/database',
mongodb: 'mongodb://user:password@localhost:27017/database',
mssql: 'mssql://user:password@localhost:1433/database',
mysql: 'mysql://user:password@localhost:3306/database',
mysql: 'mysql://user:userpassword@localhost:3306/database',
postgresql: 'postgresql://user:password@localhost:5432/database',
singlestore: 'singlestore://user:password@localhost:3306/database'
} as const;
Expand Down
20 changes: 19 additions & 1 deletion src/generators/configurations/generatePackageJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export const createPackageJson = ({
scripts['postdb:psql'] = 'bun db:down';
}

if (databaseEngine === 'mysql') {
if ((databaseEngine === 'mysql' || databaseEngine === 'mariadb') && orm === 'drizzle') {
dependencies['mysql2'] = resolveVersion('mysql2', '3.14.2');
}

Expand All @@ -202,6 +202,24 @@ export const createPackageJson = ({
scripts['postdb:mysql'] = 'bun db:down';
}

if (
databaseEngine === 'mariadb' &&
(!databaseHost || databaseHost === 'none')
) {
scripts['db:up'] =
'sh -c "docker info >/dev/null 2>&1 || sudo service docker start; docker compose -p mariadb -f db/docker-compose.db.yml up -d db"';
scripts['db:down'] =
'docker compose -p mariadb -f db/docker-compose.db.yml down';
scripts['db:reset'] =
'docker compose -p mariadb -f db/docker-compose.db.yml down -v';
scripts['db:mariadb'] =
"docker compose -p mariadb -f db/docker-compose.db.yml exec -e MYSQL_PWD=rootpassword db bash -lc 'until mariadb-admin ping -h127.0.0.1 --silent; do sleep 1; done; exec mariadb -h127.0.0.1 -uroot'";
scripts['predev'] = 'bun db:up';
scripts['predb:mariadb'] = 'bun db:up';
scripts['postdev'] = 'bun db:down';
scripts['postdb:mariadb'] = 'bun db:down';
}

if (
databaseEngine === 'sqlite' &&
(!databaseHost || databaseHost === 'none')
Expand Down
4 changes: 2 additions & 2 deletions src/generators/db/dockerInitTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ export const initTemplates = {
wait: 'until pg_isready -U user -h localhost --quiet; do sleep 1; done'
},
mariadb: {
cli: 'MYSQL_PWD=userpassword mariadb -h127.0.0.1 -u user -e',
wait: 'until mysqladmin ping -h127.0.0.1 --silent; do sleep 1; done'
cli: 'MYSQL_PWD=userpassword mariadb -h127.0.0.1 -u user database -e',
wait: 'until mariadb-admin ping -h127.0.0.1 --silent; do sleep 1; done'
},
mssql: {
cli: '/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P sapassword -Q',
Expand Down
12 changes: 10 additions & 2 deletions src/generators/db/generateDrizzleSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ const DIALECTS = {
string: 'text()',
table: 'sqliteTable',
time: "integer({ mode: 'timestamp' })"
},
mariadb: {
builders: ['json', 'mysqlTable', 'timestamp', 'varchar', 'int'],
json: 'json()',
pkg: 'mysql-core',
string: 'varchar({ length: 255 })',
table: 'mysqlTable',
time: 'timestamp()'
}
} as const;

Expand All @@ -62,7 +70,7 @@ export const generateDrizzleSchema = ({
}: GenerateSchemaProps) => {
const cfg = DIALECTS[databaseEngine];
const intBuilder =
databaseEngine === 'mysql' || databaseEngine === 'singlestore'
databaseEngine === 'mysql' || databaseEngine === 'singlestore' || databaseEngine === 'mariadb'
? 'int'
: 'integer';
const timeBuilder = builder(cfg.time);
Expand Down Expand Up @@ -98,7 +106,7 @@ export const generateDrizzleSchema = ({
}

let uidColumn: string;
if (databaseEngine === 'mysql' || databaseEngine === 'singlestore') {
if (databaseEngine === 'mysql' || databaseEngine === 'singlestore' || databaseEngine === 'mariadb') {
uidColumn = `${intBuilder}('uid').primaryKey().autoincrement()`;
} else if (databaseEngine === 'sqlite') {
uidColumn = `integer('uid').primaryKey({ autoIncrement: true })`;
Expand Down
138 changes: 61 additions & 77 deletions src/generators/db/handlerTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,15 @@ type AuthTemplateOptions = {
importLines: string;
dbType: string;
queries: QueryOperations;
handlerTypes?: HandlerType;
};

const buildSqlAuthTemplate = ({
importLines,
handlerTypes,
dbType,
queries
}: AuthTemplateOptions) => `
import { isValidProviderOption, providers } from 'citra'
${importLines}
${handlerTypes?.UserRow ? `\ntype UserRow = ${handlerTypes.UserRow}` : ''}
type UserHandlerProps = {
authProvider: string
db: ${dbType}
Expand All @@ -46,17 +43,14 @@ type CountTemplateOptions = {
importLines: string;
dbType: string;
queries: QueryOperations;
handlerTypes?: HandlerType;
};

const buildSqlCountTemplate = ({
importLines,
handlerTypes,
dbType,
queries
}: CountTemplateOptions) => `
${importLines}
${handlerTypes?.CountHistoryRow ? `\ntype CountHistoryRow = ${handlerTypes.CountHistoryRow}\n` : ''}
export const getCountHistory = async (db: ${dbType}, uid: number) => {
${queries.selectHistory}
}
Expand Down Expand Up @@ -151,21 +145,6 @@ const mongodbQueryOperations: QueryOperations = {
return user ?? null`
};

const mariadbSqlQueryOperations: QueryOperations = {
insertHistory: `await db.query('INSERT INTO count_history (count) VALUES (?)', [count])
const [rows] = await db.query('SELECT * FROM count_history ORDER BY uid DESC LIMIT 1')
return rows[0]`,
insertUser: `await db.query('INSERT INTO users (auth_sub, metadata) VALUES (?, ?)', [authSub, JSON.stringify(userIdentity)])
const [rows] = await db.query('SELECT * FROM users WHERE auth_sub = ? LIMIT 1', [authSub])
const newUser = rows[0]
if (!newUser) throw new Error('Failed to create user')
return newUser`,
selectHistory: `const [rows] = await db.query('SELECT * FROM count_history WHERE uid = ? LIMIT 1', [uid])
return rows[0] ?? null`,
selectUser: `const [rows] = await db.query('SELECT * FROM users WHERE auth_sub = ? LIMIT 1', [authSub])
return rows[0] ?? null`
};

const gelSqlQueryOperations: QueryOperations = {
insertHistory: `await db.query('INSERT INTO count_history (count) VALUES (?)', [count])
const [rows] = await db.query('SELECT * FROM count_history ORDER BY uid DESC LIMIT 1')
Expand Down Expand Up @@ -226,68 +205,66 @@ const mssqlSqlQueryOperations: QueryOperations = {

const mysqlSqlQueryOperations: QueryOperations = {
insertHistory: `
const [result] = await db.query<ResultSetHeader>(
'INSERT INTO count_history (count) VALUES (?)',
[count]
);
const insertId = result.insertId;
const [rows] = await db.query<CountHistoryRow[]>(
'SELECT * FROM count_history WHERE uid = ? LIMIT 1',
[insertId]
);
if (!rows[0]) throw new Error('Could not retrieve the newly‑inserted history');
return rows[0];
const result = await db\`
INSERT INTO count_history (count)
VALUES (\${count})
\`;

const insertId = result.lastInsertRowid;

const [row] = await db\`
SELECT *
FROM count_history
WHERE uid = \${insertId}
LIMIT 1
\`;

if (!row) throw new Error("Could not retrieve the newly-inserted history");
return row;
`,

insertUser: `
const [result] = await db.query<ResultSetHeader>(
'INSERT INTO users (auth_sub, metadata) VALUES (?, ?)',
[authSub, JSON.stringify(userIdentity)]
);
const insertId = result.insertId;
const [rows] = await db.query<UserRow[]>(
'SELECT * FROM users WHERE uid = ? LIMIT 1',
[insertId]
);
if (!rows[0]) throw new Error('Failed to create user');
return rows[0];
const result = await db\`
INSERT INTO users (auth_sub, metadata)
VALUES (\${authSub}, \${JSON.stringify(userIdentity)})
\`;

const insertId = result.lastInsertRowid;

const [row] = await db\`
SELECT *
FROM users
WHERE uid = \${insertId}
LIMIT 1
\`;

if (!row) throw new Error("Failed to create user");
return row;
`,

selectHistory: `
const [rows] = await db.query<CountHistoryRow[]>(
'SELECT * FROM count_history WHERE uid = ? LIMIT 1',
[uid]
);
return rows[0] ?? null;
const [row] = await db\`
SELECT *
FROM count_history
WHERE uid = \${uid}
LIMIT 1
\`;

return row ?? null;
`,

selectUser: `
const [rows] = await db.query<UserRow[]>(
'SELECT * FROM users WHERE auth_sub = ? LIMIT 1',
[authSub]
);
return rows[0] ?? null;
const [row] = await db\`
SELECT *
FROM users
WHERE auth_sub = \${authSub}
LIMIT 1
\`;

return row ?? null;
`
};

type HandlerType = {
CountHistoryRow: string;
UserRow: string;
};

const mysqlHandlerTypes: HandlerType = {
CountHistoryRow: `RowDataPacket & {
uid: number;
count: number;
created_at: number;
}`,
UserRow: `RowDataPacket & {
uid: number;
auth_sub: string;
metadata: string;
}`
};

const mysqlDrizzleQueryOperations: QueryOperations = {
insertHistory: `const [row] = await db
.insert(schema.countHistory)
Expand Down Expand Up @@ -336,10 +313,18 @@ const driverConfigurations = {
queries: gelSqlQueryOperations
},
'mariadb:sql:local': {
dbType: 'Pool',
importLines: `import { Pool } from 'mariadb'`,
queries: mariadbSqlQueryOperations
dbType: 'SQL',
importLines: `import { SQL } from 'bun'`,
queries: mysqlSqlQueryOperations
},
'mariadb:drizzle:local': {
dbType: 'MySql2Database<SchemaType>',
importLines: `
import { eq } from 'drizzle-orm'
import { MySql2Database } from 'drizzle-orm/mysql2'
import { schema, type SchemaType } from '../../../db/schema'`,
queries: mysqlDrizzleQueryOperations
},
'mongodb:native:local': {
dbType: 'Db',
importLines: `import { Db } from 'mongodb'`,
Expand All @@ -359,9 +344,8 @@ import { schema, type SchemaType } from '../../../db/schema'`,
queries: mysqlDrizzleQueryOperations
},
'mysql:sql:local': {
dbType: 'Pool',
handlerTypes: mysqlHandlerTypes,
importLines: `import { Pool, ResultSetHeader, RowDataPacket } from 'mysql2/promise'`,
dbType: 'SQL',
importLines: `import { SQL } from 'bun'`,
queries: mysqlSqlQueryOperations
},
'postgresql:drizzle:local': {
Expand Down
14 changes: 11 additions & 3 deletions src/generators/project/generateDBBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,16 @@ export const generateDBBlock = ({
if (!engineGroup) return '';

if (orm !== 'drizzle') {
if (databaseEngine === 'mysql' || databaseEngine === 'mariadb') {
return `
const db = new SQL(getEnv("DATABASE_URL"))
`;
}
const hostCfg = engineGroup[hostKey];
if (!hostCfg) return '';

return `
const pool = ${hostCfg.expr}
const db = ${hostCfg.expr}
`;
}

Expand All @@ -80,8 +85,11 @@ const pool = ${hostCfg.expr}
const expr = engineGroup[hostKey]?.expr ?? remoteDrizzleInit[hostKey];
if (!expr) return '';

if (databaseEngine === 'mysql') {
const mode = databaseHost === 'planetscale' ? 'planetscale' : 'default';
if (databaseEngine === 'mysql' || databaseEngine === 'mariadb') {
const mode =
databaseHost === 'planetscale' && databaseEngine === 'mysql'
? 'planetscale'
: 'default';

return `
const pool = ${expr}
Expand Down
13 changes: 8 additions & 5 deletions src/generators/project/generateImportsBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,18 @@ export const generateImportsBlock = ({
rawImports.push(...connectorImports[key]);
}

if (databaseEngine === 'mysql' && !isRemoteHost) {
rawImports.push(`import { createPool } from 'mysql2/promise'`);
if ((databaseEngine === 'mariadb' || databaseEngine === 'mysql') && noOrm) {
rawImports.push(`import { SQL } from 'bun'`);
}

if (databaseEngine === 'mysql' && orm === 'drizzle') {
rawImports.push(`import { drizzle } from 'drizzle-orm/mysql2'`);
if ((databaseEngine === 'mysql' || databaseEngine === 'mariadb') && orm === 'drizzle') {
rawImports.push(
`import { drizzle } from 'drizzle-orm/mysql2'`,
`import { createPool } from 'mysql2/promise'`
);
}

if (databaseEngine === 'mysql') {
if (databaseEngine === 'mysql' || databaseEngine === 'mariadb') {
rawImports.push(`import { getEnv } from '@absolutejs/absolute'`);
}

Expand Down