Skip to content

Commit fe0776a

Browse files
committed
refactor: create tx context
1 parent 004584e commit fe0776a

33 files changed

+314
-185
lines changed

apps/backend/src/db.ts

-21
This file was deleted.

apps/backend/src/modules/auth/auth.ts

+39-32
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { None, Option, Some } from "@undb/domain"
1414
import { env } from "@undb/env"
1515
import { createLogger } from "@undb/logger"
1616
import { type IMailService, injectMailService } from "@undb/mail"
17-
import { type IQueryBuilder, getCurrentTransaction, injectQueryBuilder } from "@undb/persistence/server"
17+
import { type IQueryBuilder, type ITxContext, injectQueryBuilder, injectTxCTX } from "@undb/persistence/server"
1818
import { type ISpaceService, injectSpaceService } from "@undb/space"
1919
import { Context, Elysia, t } from "elysia"
2020
import type { Session, User } from "lucia"
@@ -25,7 +25,6 @@ import { alphabet, generateRandomString, sha256 } from "oslo/crypto"
2525
import { encodeHex } from "oslo/encoding"
2626
import { omit } from "radash"
2727
import { v7 } from "uuid"
28-
import { withTransaction } from "../../db"
2928
import { injectLucia } from "./auth.provider"
3029
import { OAuth } from "./oauth/oauth"
3130

@@ -52,10 +51,12 @@ export class Auth {
5251
private readonly mailService: IMailService,
5352
@injectLucia()
5453
private readonly lucia: Lucia,
54+
@injectTxCTX()
55+
private readonly txContext: ITxContext,
5556
) {}
5657

5758
async #generateEmailVerificationCode(userId: string, email: string): Promise<string> {
58-
const tx = getCurrentTransaction()
59+
const tx = this.txContext.getCurrentTransaction()
5960
await tx.deleteFrom("undb_email_verification_code").where("user_id", "=", userId).execute()
6061
const code = env.UNDB_MOCK_MAIL_CODE || generateRandomString(6, alphabet("0-9"))
6162
await tx
@@ -71,29 +72,32 @@ export class Auth {
7172
}
7273

7374
async #verifyVerificationCode(user: User, code: string): Promise<boolean> {
74-
return (getCurrentTransaction() ?? this.queryBuilder).transaction().execute(async (tx) => {
75-
const databaseCode = await tx
76-
.selectFrom("undb_email_verification_code")
77-
.selectAll()
78-
.where("user_id", "=", user.id)
79-
.executeTakeFirst()
80-
if (!databaseCode || databaseCode.code !== code) {
81-
return false
82-
}
83-
await tx.deleteFrom("undb_email_verification_code").where("id", "=", databaseCode.id).execute()
75+
return this.txContext
76+
.getCurrentTransaction()
77+
.transaction()
78+
.execute(async (tx) => {
79+
const databaseCode = await tx
80+
.selectFrom("undb_email_verification_code")
81+
.selectAll()
82+
.where("user_id", "=", user.id)
83+
.executeTakeFirst()
84+
if (!databaseCode || databaseCode.code !== code) {
85+
return false
86+
}
87+
await tx.deleteFrom("undb_email_verification_code").where("id", "=", databaseCode.id).execute()
8488

85-
if (!isWithinExpirationDate(new Date(databaseCode.expires_at))) {
86-
return false
87-
}
88-
if (databaseCode.email !== user.email) {
89-
return false
90-
}
91-
return true
92-
})
89+
if (!isWithinExpirationDate(new Date(databaseCode.expires_at))) {
90+
return false
91+
}
92+
if (databaseCode.email !== user.email) {
93+
return false
94+
}
95+
return true
96+
})
9397
}
9498

9599
async #createPasswordResetToken(userId: string): Promise<string> {
96-
const db = getCurrentTransaction() ?? this.queryBuilder
100+
const db = this.txContext.getCurrentTransaction()
97101
await db.deleteFrom("undb_password_reset_token").where("user_id", "=", userId).execute()
98102
const tokenId = generateIdFromEntropySize(25) // 40 character
99103
const tokenHash = encodeHex(await sha256(new TextEncoder().encode(tokenId)))
@@ -206,8 +210,9 @@ export class Auth {
206210
},
207211
})
208212

209-
await withTransaction(this.queryBuilder)(async () => {
210-
await getCurrentTransaction()
213+
await this.txContext.withTransaction(async () => {
214+
await this.txContext
215+
.getCurrentTransaction()
211216
.insertInto("undb_user")
212217
.values({
213218
email: adminEmail,
@@ -326,8 +331,9 @@ export class Auth {
326331
},
327332
})
328333

329-
await withTransaction(this.queryBuilder)(async () => {
330-
await getCurrentTransaction()
334+
await this.txContext.withTransaction(async () => {
335+
await this.txContext
336+
.getCurrentTransaction()
331337
.insertInto("undb_user")
332338
.values({
333339
email,
@@ -470,9 +476,9 @@ export class Auth {
470476
.post(
471477
"/api/reset-password",
472478
async (ctx) => {
473-
return withTransaction(this.queryBuilder)(async () => {
479+
return this.txContext.withTransaction(async () => {
474480
const email = ctx.body.email
475-
const tx = getCurrentTransaction() ?? this.queryBuilder
481+
const tx = this.txContext.getCurrentTransaction()
476482
const user = await tx.selectFrom("undb_user").selectAll().where("email", "=", email).executeTakeFirst()
477483
if (!user) {
478484
return new Response(null, {
@@ -505,8 +511,8 @@ export class Auth {
505511
.post(
506512
"/api/reset-password/:token",
507513
async (ctx) => {
508-
return withTransaction(this.queryBuilder)(async () => {
509-
const tx = getCurrentTransaction() ?? this.queryBuilder
514+
return this.txContext.withTransaction(async () => {
515+
const tx = this.txContext.getCurrentTransaction()
510516

511517
const password = ctx.body.password
512518
const verificationToken = ctx.params.token
@@ -589,7 +595,8 @@ export class Auth {
589595
}
590596

591597
await this.lucia.invalidateUserSessions(user.id)
592-
await (getCurrentTransaction() ?? this.queryBuilder)
598+
await this.txContext
599+
.getCurrentTransaction()
593600
.updateTable("undb_user")
594601
.set("email_verified", true)
595602
.where("id", "=", user.id)
@@ -615,7 +622,7 @@ export class Auth {
615622
.get(
616623
"/invitation/:invitationId/accept",
617624
async (ctx) => {
618-
return withTransaction(this.queryBuilder)(async () => {
625+
return this.txContext.withTransaction(async () => {
619626
const { invitationId } = ctx.params
620627
await this.commandBus.execute(new AcceptInvitationCommand({ id: invitationId }))
621628

apps/backend/src/modules/auth/oauth/github.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ import { type ISpaceMemberService, injectSpaceMemberService } from "@undb/authz"
22
import { setContextValue } from "@undb/context/server"
33
import { singleton } from "@undb/di"
44
import { createLogger } from "@undb/logger"
5-
import { type IQueryBuilder, getCurrentTransaction, injectQueryBuilder } from "@undb/persistence/server"
5+
import { type IQueryBuilder, type ITxContext, injectQueryBuilder, injectTxCTX } from "@undb/persistence/server"
66
import { type ISpaceService, injectSpaceService } from "@undb/space"
77
import { GitHub } from "arctic"
88
import { Elysia } from "elysia"
99
import { type Lucia, generateIdFromEntropySize } from "lucia"
1010
import { serializeCookie } from "oslo/cookie"
1111
import { OAuth2RequestError, generateState } from "oslo/oauth2"
12-
import { withTransaction } from "../../../db"
1312
import { injectLucia } from "../auth.provider"
1413
import { injectGithubProvider } from "./github.provider"
1514

@@ -26,6 +25,8 @@ export class GithubOAuth {
2625
private readonly github: GitHub,
2726
@injectLucia()
2827
private readonly lucia: Lucia,
28+
@injectTxCTX()
29+
private readonly txContext: ITxContext,
2930
) {}
3031

3132
private logger = createLogger(GithubOAuth.name)
@@ -34,7 +35,7 @@ export class GithubOAuth {
3435
return new Elysia()
3536
.get("/login/github", async (ctx) => {
3637
const state = generateState()
37-
const url = await this.github.createAuthorizationURL(state, { scopes: ["user:email"] })
38+
const url = this.github.createAuthorizationURL(state, ["user:email"])
3839
return new Response(null, {
3940
status: 302,
4041
headers: {
@@ -143,8 +144,8 @@ export class GithubOAuth {
143144
})
144145
}
145146
const userId = generateIdFromEntropySize(10) // 16 characters long
146-
const space = await withTransaction(this.queryBuilder)(async () => {
147-
const tx = getCurrentTransaction()
147+
const space = await this.txContext.withTransaction(async () => {
148+
const tx = this.txContext.getCurrentTransaction()
148149
await tx
149150
.insertInto("undb_user")
150151
.values({

apps/backend/src/modules/auth/oauth/google.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ import { type ISpaceMemberService, injectSpaceMemberService } from "@undb/authz"
22
import { setContextValue } from "@undb/context/server"
33
import { singleton } from "@undb/di"
44
import { createLogger } from "@undb/logger"
5-
import { type IQueryBuilder, getCurrentTransaction, injectQueryBuilder } from "@undb/persistence/server"
5+
import { type IQueryBuilder, type ITxContext, injectQueryBuilder, injectTxCTX } from "@undb/persistence/server"
66
import { type ISpaceService, injectSpaceService } from "@undb/space"
77
import { Google, generateCodeVerifier } from "arctic"
88
import { env } from "bun"
99
import { Elysia } from "elysia"
1010
import { type Lucia, generateIdFromEntropySize } from "lucia"
1111
import { OAuth2RequestError, generateState } from "oslo/oauth2"
12-
import { withTransaction } from "../../../db"
1312
import { injectLucia } from "../auth.provider"
1413
import { injectGoogleProvider } from "./google.provider"
1514

@@ -26,6 +25,8 @@ export class GoogleOAuth {
2625
private readonly google: Google,
2726
@injectLucia()
2827
private readonly lucia: Lucia,
28+
@injectTxCTX()
29+
private readonly txContext: ITxContext,
2930
) {}
3031

3132
private logger = createLogger(GoogleOAuth.name)
@@ -35,9 +36,7 @@ export class GoogleOAuth {
3536
.get("/login/google", async (ctx) => {
3637
const state = generateState()
3738
const codeVerifier = generateCodeVerifier()
38-
const url = await this.google.createAuthorizationURL(state, codeVerifier, {
39-
scopes: ["email", "profile"],
40-
})
39+
const url = this.google.createAuthorizationURL(state, codeVerifier, ["email", "profile"])
4140

4241
ctx.cookie["state"].set({
4342
value: state,
@@ -133,8 +132,8 @@ export class GoogleOAuth {
133132
})
134133
}
135134
const userId = generateIdFromEntropySize(10) // 16 characters long
136-
const space = await withTransaction(this.queryBuilder)(async () => {
137-
const tx = getCurrentTransaction()
135+
const space = await this.txContext.withTransaction(async () => {
136+
const tx = this.txContext.getCurrentTransaction()
138137
await tx
139138
.insertInto("undb_user")
140139
.values({

apps/backend/src/modules/openapi/record.openapi.ts

+14-12
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import {
1313
import { CommandBus, QueryBus } from "@undb/cqrs"
1414
import { inject, singleton } from "@undb/di"
1515
import { Option, type ICommandBus, type IQueryBus, type PaginatedDTO } from "@undb/domain"
16-
import { injectQueryBuilder, type IQueryBuilder } from "@undb/persistence/server"
16+
import type { ITxContext } from "@undb/persistence/server"
17+
import { injectQueryBuilder, injectTxCTX, type IQueryBuilder } from "@undb/persistence/server"
1718
import {
1819
GetAggregatesQuery,
1920
GetPivotDataQuery,
@@ -22,7 +23,6 @@ import {
2223
} from "@undb/queries"
2324
import { RecordDO, type IRecordReadableValueDTO } from "@undb/table"
2425
import Elysia, { t } from "elysia"
25-
import { withTransaction } from "../../db"
2626

2727
@singleton()
2828
export class RecordOpenApi {
@@ -34,6 +34,8 @@ export class RecordOpenApi {
3434
private readonly commandBus: ICommandBus,
3535
@injectQueryBuilder()
3636
private readonly qb: IQueryBuilder,
37+
@injectTxCTX()
38+
private readonly txContext: ITxContext,
3739
) {}
3840

3941
public route() {
@@ -184,7 +186,7 @@ export class RecordOpenApi {
184186
async (ctx) => {
185187
const baseName = decodeURIComponent(ctx.params.baseName)
186188
const tableName = decodeURIComponent(ctx.params.tableName)
187-
return withTransaction(this.qb)(() =>
189+
return this.txContext.withTransaction(() =>
188190
this.commandBus.execute(new CreateRecordCommand({ baseName, tableName, values: ctx.body.values })),
189191
)
190192
},
@@ -203,7 +205,7 @@ export class RecordOpenApi {
203205
async (ctx) => {
204206
const baseName = decodeURIComponent(ctx.params.baseName)
205207
const tableName = decodeURIComponent(ctx.params.tableName)
206-
return withTransaction(this.qb)(() =>
208+
return this.txContext.withTransaction(() =>
207209
this.commandBus.execute(new CreateRecordsCommand({ baseName, tableName, records: ctx.body.records })),
208210
)
209211
},
@@ -222,7 +224,7 @@ export class RecordOpenApi {
222224
async (ctx) => {
223225
const baseName = decodeURIComponent(ctx.params.baseName)
224226
const tableName = decodeURIComponent(ctx.params.tableName)
225-
return withTransaction(this.qb)(() =>
227+
return this.txContext.withTransaction(() =>
226228
this.commandBus.execute(
227229
new UpdateRecordCommand({
228230
tableName,
@@ -248,7 +250,7 @@ export class RecordOpenApi {
248250
async (ctx) => {
249251
const baseName = decodeURIComponent(ctx.params.baseName)
250252
const tableName = decodeURIComponent(ctx.params.tableName)
251-
return withTransaction(this.qb)(() =>
253+
return this.txContext.withTransaction(() =>
252254
this.commandBus.execute(
253255
new BulkUpdateRecordsCommand({
254256
tableName,
@@ -278,7 +280,7 @@ export class RecordOpenApi {
278280
async (ctx) => {
279281
const baseName = decodeURIComponent(ctx.params.baseName)
280282
const tableName = decodeURIComponent(ctx.params.tableName)
281-
return withTransaction(this.qb)(() =>
283+
return this.txContext.withTransaction(() =>
282284
this.commandBus.execute(new DuplicateRecordCommand({ baseName, tableName, id: ctx.params.recordId })),
283285
)
284286
},
@@ -298,7 +300,7 @@ export class RecordOpenApi {
298300
const tableName = decodeURIComponent(ctx.params.tableName)
299301
const recordId = ctx.params.recordId
300302
const field = ctx.params.field
301-
return withTransaction(this.qb)(async () => {
303+
return this.txContext.withTransaction(async () => {
302304
const result = (await this.commandBus.execute(
303305
new TriggerRecordButtonCommand({ baseName, tableName, recordId, field }),
304306
)) as Option<RecordDO>
@@ -326,7 +328,7 @@ export class RecordOpenApi {
326328
async (ctx) => {
327329
const baseName = decodeURIComponent(ctx.params.baseName)
328330
const tableName = decodeURIComponent(ctx.params.tableName)
329-
return withTransaction(this.qb)(() =>
331+
return this.txContext.withTransaction(() =>
330332
this.commandBus.execute(
331333
new BulkDuplicateRecordsCommand({
332334
baseName,
@@ -352,7 +354,7 @@ export class RecordOpenApi {
352354
async (ctx) => {
353355
const baseName = decodeURIComponent(ctx.params.baseName)
354356
const tableName = decodeURIComponent(ctx.params.tableName)
355-
return withTransaction(this.qb)(() =>
357+
return this.txContext.withTransaction(() =>
356358
this.commandBus.execute(new DeleteRecordCommand({ baseName, tableName, id: ctx.params.recordId })),
357359
)
358360
},
@@ -370,7 +372,7 @@ export class RecordOpenApi {
370372
async (ctx) => {
371373
const baseName = decodeURIComponent(ctx.params.baseName)
372374
const tableName = decodeURIComponent(ctx.params.tableName)
373-
return withTransaction(this.qb)(() =>
375+
return this.txContext.withTransaction(() =>
374376
this.commandBus.execute(
375377
new BulkDeleteRecordsCommand({
376378
baseName,
@@ -397,7 +399,7 @@ export class RecordOpenApi {
397399
const baseName = decodeURIComponent(ctx.params.baseName)
398400
const tableName = decodeURIComponent(ctx.params.tableName)
399401
const formName = decodeURIComponent(ctx.params.formName)
400-
return withTransaction(this.qb)(() =>
402+
return this.txContext.withTransaction(() =>
401403
this.commandBus.execute(
402404
new SubmitFormCommand({ baseName, tableName, form: formName, values: ctx.body.values }),
403405
),

0 commit comments

Comments
 (0)