Merge remote-tracking branch 'origin/master' into 3214-feature-x-com-sendcoins-4-activate-email-and-event-actions-in-federation-modul

This commit is contained in:
clauspeterhuebner 2025-12-17 01:30:52 +01:00
commit 76399f49c3
38 changed files with 310 additions and 176 deletions

View File

@ -23,21 +23,22 @@ module.exports = {
'@repository/(.*)': '<rootDir>/src/typeorm/repository/$1', '@repository/(.*)': '<rootDir>/src/typeorm/repository/$1',
'@typeorm/(.*)': '<rootDir>/src/typeorm/$1', '@typeorm/(.*)': '<rootDir>/src/typeorm/$1',
'@test/(.*)': '<rootDir>/test/$1', '@test/(.*)': '<rootDir>/test/$1',
'@entity/(.*)':
process.env.NODE_ENV === 'development'
? '<rootDir>/../database/entity/$1'
: '<rootDir>/../database/build/entity/$1',
'@logging/(.*)':
process.env.NODE_ENV === 'development'
? '<rootDir>/../database/logging/$1'
: '<rootDir>/../database/build/logging/$1',
'@dbTools/(.*)':
process.env.NODE_ENV === 'development'
? '<rootDir>/../database/src/$1'
: '<rootDir>/../database/build/src/$1',
'@config/(.*)':
process.env.NODE_ENV === 'development'
? '<rootDir>/../config/src/$1'
: '<rootDir>/../config/build/$1',
}, },
transform: {
'^.+\\.(t|j)sx?$': ['@swc/jest', {
jsc: {
parser: {
syntax: 'typescript',
decorators: true,
tsc: true,
},
transform: {
decoratorMetadata: true,
},
}
}],
},
transformIgnorePatterns: [
'/node_modules/(?!drizzle-orm/)',
],
} }

View File

@ -39,6 +39,7 @@
"@swc/cli": "^0.7.3", "@swc/cli": "^0.7.3",
"@swc/core": "^1.11.24", "@swc/core": "^1.11.24",
"@swc/helpers": "^0.5.17", "@swc/helpers": "^0.5.17",
"@swc/jest": "^0.2.38",
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"@types/email-templates": "^10.0.4", "@types/email-templates": "^10.0.4",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",

View File

@ -1,10 +1,15 @@
import { OpenaiThreads, User } from 'database' import {
dbDeleteOpenaiThread,
dbFindNewestCreatedOpenaiThreadByUserId,
dbInsertOpenaiThread,
dbUpdateOpenaiThread,
User,
} from 'database'
import { getLogger } from 'log4js' import { getLogger } from 'log4js'
import { OpenAI } from 'openai' import { OpenAI } from 'openai'
import { Message } from 'openai/resources/beta/threads/messages' import { Message } from 'openai/resources/beta/threads/messages'
import { httpsAgent } from '@/apis/ConnectionAgents' import { httpsAgent } from '@/apis/ConnectionAgents'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { Message as MessageModel } from './model/Message' import { Message as MessageModel } from './model/Message'
@ -64,10 +69,7 @@ export class OpenaiClient {
messages: [initialMessage], messages: [initialMessage],
}) })
// store id in db because it isn't possible to list all open threads via openai api // store id in db because it isn't possible to list all open threads via openai api
const openaiThreadEntity = OpenaiThreads.create() await dbInsertOpenaiThread(messageThread.id, user.id)
openaiThreadEntity.id = messageThread.id
openaiThreadEntity.userId = user.id
await openaiThreadEntity.save()
logger.info(`Created new message thread: ${messageThread.id}`) logger.info(`Created new message thread: ${messageThread.id}`)
return messageThread.id return messageThread.id
@ -79,10 +81,7 @@ export class OpenaiClient {
* @returns * @returns
*/ */
public async resumeThread(user: User): Promise<MessageModel[]> { public async resumeThread(user: User): Promise<MessageModel[]> {
const openaiThreadEntity = await OpenaiThreads.findOne({ const openaiThreadEntity = await dbFindNewestCreatedOpenaiThreadByUserId(user.id)
where: { userId: user.id },
order: { createdAt: 'DESC' },
})
if (!openaiThreadEntity) { if (!openaiThreadEntity) {
logger.warn(`No openai thread found for user: ${user.id}`) logger.warn(`No openai thread found for user: ${user.id}`)
return [] return []
@ -126,7 +125,7 @@ export class OpenaiClient {
public async deleteThread(threadId: string): Promise<boolean> { public async deleteThread(threadId: string): Promise<boolean> {
const [, result] = await Promise.all([ const [, result] = await Promise.all([
OpenaiThreads.delete({ id: threadId }), dbDeleteOpenaiThread(threadId),
this.openai.beta.threads.del(threadId), this.openai.beta.threads.del(threadId),
]) ])
if (result.deleted) { if (result.deleted) {
@ -144,10 +143,7 @@ export class OpenaiClient {
} }
public async runAndGetLastNewMessage(threadId: string): Promise<MessageModel> { public async runAndGetLastNewMessage(threadId: string): Promise<MessageModel> {
const updateOpenAiThreadResolver = OpenaiThreads.update( const updateOpenAiThreadResolver = dbUpdateOpenaiThread(threadId)
{ id: threadId },
{ updatedAt: new Date() },
)
const run = await this.openai.beta.threads.runs.createAndPoll(threadId, { const run = await this.openai.beta.threads.runs.createAndPoll(threadId, {
assistant_id: CONFIG.OPENAI_ASSISTANT_ID, assistant_id: CONFIG.OPENAI_ASSISTANT_ID,
}) })

View File

@ -4,7 +4,7 @@ import { getLogger } from 'config-schema/test/testSetup'
import { AppDatabase, FederatedCommunity as DbFederatedCommunity } from 'database' import { AppDatabase, FederatedCommunity as DbFederatedCommunity } from 'database'
import { GraphQLClient } from 'graphql-request' import { GraphQLClient } from 'graphql-request'
import { Response } from 'graphql-request/dist/types' import { Response } from 'graphql-request/dist/types'
import { DataSource, Not } from 'typeorm' import { Not } from 'typeorm'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { validateCommunities } from './validateCommunities' import { validateCommunities } from './validateCommunities'
@ -13,26 +13,22 @@ const federationClientLogger = getLogger(
`${LOG4JS_BASE_CATEGORY_NAME}.federation.client.1_0.FederationClient`, `${LOG4JS_BASE_CATEGORY_NAME}.federation.client.1_0.FederationClient`,
) )
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
beforeAll(async () => { beforeAll(async () => {
testEnv = await testEnvironment(logger) testEnv = await testEnvironment(logger)
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
// await cleanDB() // await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('validate Communities', () => { describe('validate Communities', () => {

View File

@ -9,7 +9,6 @@ import {
} from 'database' } from 'database'
import { createCommunity, createVerifiedFederatedCommunity } from 'database/src/seeds/community' import { createCommunity, createVerifiedFederatedCommunity } from 'database/src/seeds/community'
import { GraphQLError } from 'graphql/error/GraphQLError' import { GraphQLError } from 'graphql/error/GraphQLError'
import { DataSource } from 'typeorm'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { userFactory } from '@/seeds/factory/user' import { userFactory } from '@/seeds/factory/user'
@ -29,12 +28,10 @@ CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER = 1000
// to do: We need a setup for the tests that closes the connection // to do: We need a setup for the tests that closes the connection
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let query: ApolloServerTestClient['query'] let query: ApolloServerTestClient['query']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
@ -48,7 +45,6 @@ beforeAll(async () => {
testEnv = await testEnvironment(getLogger('apollo')) testEnv = await testEnvironment(getLogger('apollo'))
mutate = testEnv.mutate mutate = testEnv.mutate
query = testEnv.query query = testEnv.query
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
// reset id auto increment // reset id auto increment
@ -57,8 +53,7 @@ beforeAll(async () => {
}) })
afterAll(async () => { afterAll(async () => {
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
// real valid ed25519 key pairs // real valid ed25519 key pairs

View File

@ -4,7 +4,6 @@ import { getLogger } from 'config-schema/test/testSetup'
import { AppDatabase, ContributionLink as DbContributionLink, Event as DbEvent } from 'database' import { AppDatabase, ContributionLink as DbContributionLink, Event as DbEvent } from 'database'
import { Decimal } from 'decimal.js-light' import { Decimal } from 'decimal.js-light'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { DataSource } from 'typeorm'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { EventType } from '@/event/Events' import { EventType } from '@/event/Events'
import { userFactory } from '@/seeds/factory/user' import { userFactory } from '@/seeds/factory/user'
@ -24,12 +23,10 @@ const logErrorLogger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`)
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let query: ApolloServerTestClient['query'] let query: ApolloServerTestClient['query']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
@ -37,7 +34,6 @@ beforeAll(async () => {
testEnv = await testEnvironment() testEnv = await testEnvironment()
mutate = testEnv.mutate mutate = testEnv.mutate
query = testEnv.query query = testEnv.query
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
@ -46,8 +42,7 @@ beforeAll(async () => {
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('Contribution Links', () => { describe('Contribution Links', () => {

View File

@ -5,7 +5,6 @@ import { getLogger } from 'config-schema/test/testSetup'
import { sendAddedContributionMessageEmail } from 'core' import { sendAddedContributionMessageEmail } from 'core'
import { AppDatabase, Contribution as DbContribution, Event as DbEvent } from 'database' import { AppDatabase, Contribution as DbContribution, Event as DbEvent } from 'database'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { DataSource } from 'typeorm'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { EventType } from '@/event/Events' import { EventType } from '@/event/Events'
import { userFactory } from '@/seeds/factory/user' import { userFactory } from '@/seeds/factory/user'
@ -39,12 +38,10 @@ jest.mock('core', () => {
}) })
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
let result: any let result: any
@ -52,15 +49,13 @@ let result: any
beforeAll(async () => { beforeAll(async () => {
testEnv = await testEnvironment(logger) testEnv = await testEnvironment(logger)
mutate = testEnv.mutate mutate = testEnv.mutate
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('ContributionMessageResolver', () => { describe('ContributionMessageResolver', () => {

View File

@ -26,7 +26,7 @@ import {
import { Decimal } from 'decimal.js-light' import { Decimal } from 'decimal.js-light'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { getLogger as originalGetLogger } from 'log4js' import { getLogger as originalGetLogger } from 'log4js'
import { DataSource, Equal } from 'typeorm' import { Equal } from 'typeorm'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { EventType } from '@/event/Events' import { EventType } from '@/event/Events'
import { creations } from '@/seeds/creation/index' import { creations } from '@/seeds/creation/index'
@ -74,12 +74,10 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.server.LogError`)
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let query: ApolloServerTestClient['query'] let query: ApolloServerTestClient['query']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
let creation: Contribution | null let creation: Contribution | null
@ -95,15 +93,13 @@ beforeAll(async () => {
testEnv = await testEnvironment(originalGetLogger('apollo')) testEnv = await testEnvironment(originalGetLogger('apollo'))
mutate = testEnv.mutate mutate = testEnv.mutate
query = testEnv.query query = testEnv.query
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('ContributionResolver', () => { describe('ContributionResolver', () => {

View File

@ -3,7 +3,6 @@ import { ApolloServerTestClient } from 'apollo-server-testing'
import { CONFIG as CORE_CONFIG } from 'core' import { CONFIG as CORE_CONFIG } from 'core'
import { AppDatabase, User as DbUser } from 'database' import { AppDatabase, User as DbUser } from 'database'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { DataSource } from 'typeorm'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { writeHomeCommunityEntry } from '@/seeds/community' import { writeHomeCommunityEntry } from '@/seeds/community'
import { createUser, forgotPassword, setPassword } from '@/seeds/graphql/mutations' import { createUser, forgotPassword, setPassword } from '@/seeds/graphql/mutations'
@ -11,12 +10,10 @@ import { queryOptIn } from '@/seeds/graphql/queries'
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let query: ApolloServerTestClient['query'] let query: ApolloServerTestClient['query']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
@ -28,15 +25,13 @@ beforeAll(async () => {
testEnv = await testEnvironment() testEnv = await testEnvironment()
mutate = testEnv.mutate mutate = testEnv.mutate
query = testEnv.query query = testEnv.query
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('EmailOptinCodes', () => { describe('EmailOptinCodes', () => {

View File

@ -14,21 +14,18 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.graphql.resolver.Klicktip
let testEnv: any let testEnv: any
let mutate: any let mutate: any
let con: any
let db: AppDatabase let db: AppDatabase
beforeAll(async () => { beforeAll(async () => {
testEnv = await testEnvironment(logger) testEnv = await testEnvironment(logger)
mutate = testEnv.mutate mutate = testEnv.mutate
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('KlicktippResolver', () => { describe('KlicktippResolver', () => {

View File

@ -48,12 +48,10 @@ CONFIG.DLT_ACTIVE = false
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let query: ApolloServerTestClient['query'] let query: ApolloServerTestClient['query']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
@ -63,7 +61,6 @@ beforeAll(async () => {
testEnv = await testEnvironment() testEnv = await testEnvironment()
mutate = testEnv.mutate mutate = testEnv.mutate
query = testEnv.query query = testEnv.query
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, bibiBloxberg)
@ -72,8 +69,7 @@ beforeAll(async () => {
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('TransactionLinkResolver', () => { describe('TransactionLinkResolver', () => {

View File

@ -6,13 +6,10 @@ import {
AppDatabase, AppDatabase,
Community as DbCommunity, Community as DbCommunity,
Event as DbEvent, Event as DbEvent,
FederatedCommunity as DbFederatedCommunity,
DltTransaction,
Transaction, Transaction,
User, User,
} from 'database' } from 'database'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { DataSource, In } from 'typeorm'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
// import { CONFIG } from '@/config' // import { CONFIG } from '@/config'
@ -43,11 +40,9 @@ CORE_CONFIG.EMAIL = false
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let query: ApolloServerTestClient['query'] let query: ApolloServerTestClient['query']
let con: DataSource
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
@ -55,14 +50,12 @@ beforeAll(async () => {
testEnv = await testEnvironment(logger) testEnv = await testEnvironment(logger)
mutate = testEnv.mutate mutate = testEnv.mutate
query = testEnv.query query = testEnv.query
con = testEnv.con
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() // close() await testEnv.db.destroy()
await testEnv.db.getRedisClient().quit()
}) })
let bobData: any let bobData: any

View File

@ -25,7 +25,6 @@ import {
UserRole, UserRole,
} from 'database' } from 'database'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { DataSource } from 'typeorm'
import { v4 as uuidv4, validate as validateUUID, version as versionUUID } from 'uuid' import { v4 as uuidv4, validate as validateUUID, version as versionUUID } from 'uuid'
import { subscribe } from '@/apis/KlicktippController' import { subscribe } from '@/apis/KlicktippController'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
@ -100,12 +99,10 @@ let admin: User
let user: User let user: User
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let query: ApolloServerTestClient['query'] let query: ApolloServerTestClient['query']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
@ -113,7 +110,6 @@ beforeAll(async () => {
testEnv = await testEnvironment(getLogger('apollo')) testEnv = await testEnvironment(getLogger('apollo'))
mutate = testEnv.mutate mutate = testEnv.mutate
query = testEnv.query query = testEnv.query
con = testEnv.con
db = testEnv.db db = testEnv.db
CONFIG.HUMHUB_ACTIVE = false CONFIG.HUMHUB_ACTIVE = false
CONFIG.DLT_ACTIVE = false CONFIG.DLT_ACTIVE = false
@ -122,8 +118,7 @@ beforeAll(async () => {
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('UserResolver', () => { describe('UserResolver', () => {

View File

@ -6,7 +6,6 @@ import { Decimal } from 'decimal.js-light'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
// import { TRANSACTIONS_LOCK } from 'database' // import { TRANSACTIONS_LOCK } from 'database'
import { Mutex } from 'redis-semaphore' import { Mutex } from 'redis-semaphore'
import { DataSource } from 'typeorm'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { creationFactory, nMonthsBefore } from '@/seeds/factory/creation' import { creationFactory, nMonthsBefore } from '@/seeds/factory/creation'
@ -30,24 +29,20 @@ CONFIG.DLT_ACTIVE = false
CORE_CONFIG.EMAIL = false CORE_CONFIG.EMAIL = false
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let con: DataSource
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
beforeAll(async () => { beforeAll(async () => {
testEnv = await testEnvironment() testEnv = await testEnvironment()
mutate = testEnv.mutate mutate = testEnv.mutate
con = testEnv.con
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await testEnv.db.destroy()
await testEnv.db.getRedisClient().quit()
}) })
type WorkData = { start: number; end: number } type WorkData = { start: number; end: number }

View File

@ -1,7 +1,6 @@
import { cleanDB, contributionDateFormatter, testEnvironment } from '@test/helpers' import { cleanDB, contributionDateFormatter, testEnvironment } from '@test/helpers'
import { ApolloServerTestClient } from 'apollo-server-testing' import { ApolloServerTestClient } from 'apollo-server-testing'
import { AppDatabase, Contribution, User } from 'database' import { AppDatabase, Contribution, User } from 'database'
import { DataSource } from 'typeorm'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { userFactory } from '@/seeds/factory/user' import { userFactory } from '@/seeds/factory/user'
@ -16,27 +15,23 @@ jest.mock('@/password/EncryptorUtils')
CONFIG.HUMHUB_ACTIVE = false CONFIG.HUMHUB_ACTIVE = false
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
beforeAll(async () => { beforeAll(async () => {
testEnv = await testEnvironment() testEnv = await testEnvironment()
mutate = testEnv.mutate mutate = testEnv.mutate
con = testEnv.con
db = testEnv.db db = testEnv.db
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
const setZeroHours = (date: Date): Date => { const setZeroHours = (date: Date): Date => {

View File

@ -1,7 +1,6 @@
import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { cleanDB, resetToken, testEnvironment } from '@test/helpers'
import { ApolloServerTestClient } from 'apollo-server-testing' import { ApolloServerTestClient } from 'apollo-server-testing'
import { AppDatabase, Event as DbEvent } from 'database' import { AppDatabase, Event as DbEvent } from 'database'
import { DataSource } from 'typeorm'
import { addFieldsToSubscriber } from '@/apis/KlicktippController' import { addFieldsToSubscriber } from '@/apis/KlicktippController'
import { creations } from '@/seeds/creation' import { creations } from '@/seeds/creation'
@ -17,27 +16,23 @@ jest.mock('@/apis/KlicktippController')
jest.mock('@/password/EncryptorUtils') jest.mock('@/password/EncryptorUtils')
let mutate: ApolloServerTestClient['mutate'] let mutate: ApolloServerTestClient['mutate']
let con: DataSource
let db: AppDatabase let db: AppDatabase
let testEnv: { let testEnv: {
mutate: ApolloServerTestClient['mutate'] mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query'] query: ApolloServerTestClient['query']
con: DataSource
db: AppDatabase db: AppDatabase
} }
beforeAll(async () => { beforeAll(async () => {
testEnv = await testEnvironment() testEnv = await testEnvironment()
mutate = testEnv.mutate mutate = testEnv.mutate
con = testEnv.con
db = testEnv.db db = testEnv.db
await DbEvent.clear() await DbEvent.clear()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.destroy() await db.destroy()
await db.getRedisClient().quit()
}) })
describe('klicktipp', () => { describe('klicktipp', () => {

View File

@ -101,6 +101,7 @@
"@swc/cli": "^0.7.3", "@swc/cli": "^0.7.3",
"@swc/core": "^1.11.24", "@swc/core": "^1.11.24",
"@swc/helpers": "^0.5.17", "@swc/helpers": "^0.5.17",
"@swc/jest": "^0.2.38",
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"@types/email-templates": "^10.0.4", "@types/email-templates": "^10.0.4",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
@ -226,6 +227,7 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"decimal.js-light": "^2.5.1", "decimal.js-light": "^2.5.1",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"drizzle-orm": "^0.44.7",
"esbuild": "^0.25.2", "esbuild": "^0.25.2",
"geojson": "^0.5.0", "geojson": "^0.5.0",
"ioredis": "^5.8.2", "ioredis": "^5.8.2",
@ -247,6 +249,7 @@
"@types/geojson": "^7946.0.13", "@types/geojson": "^7946.0.13",
"@types/mysql": "^2.15.27", "@types/mysql": "^2.15.27",
"@types/node": "^18.7.14", "@types/node": "^18.7.14",
"drizzle-kit": "^0.31.7",
"random-bigint": "^0.0.1", "random-bigint": "^0.0.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^4.9.5", "typescript": "^4.9.5",
@ -304,6 +307,7 @@
"@swc/cli": "^0.7.3", "@swc/cli": "^0.7.3",
"@swc/core": "^1.11.24", "@swc/core": "^1.11.24",
"@swc/helpers": "^0.5.17", "@swc/helpers": "^0.5.17",
"@swc/jest": "^0.2.38",
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"@types/express": "4.17.21", "@types/express": "4.17.21",
"@types/jest": "27.0.2", "@types/jest": "27.0.2",
@ -660,8 +664,14 @@
"@csstools/selector-specificity": ["@csstools/selector-specificity@5.0.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.0.0" } }, "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw=="], "@csstools/selector-specificity": ["@csstools/selector-specificity@5.0.0", "", { "peerDependencies": { "postcss-selector-parser": "^7.0.0" } }, "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw=="],
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
"@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.2.1", "", {}, "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg=="], "@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.2.1", "", {}, "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg=="],
"@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
"@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
@ -1892,6 +1902,10 @@
"dotenv-webpack": ["dotenv-webpack@7.1.1", "", { "dependencies": { "dotenv-defaults": "^2.0.2" }, "peerDependencies": { "webpack": "^4 || ^5" } }, "sha512-xw/19VqHDkXALtBOJAnnrSU/AZDIQRXczAmJyp0lZv6SH2aBLzUTl96W1MVryJZ7okZ+djZS4Gj4KlZ0xP7deA=="], "dotenv-webpack": ["dotenv-webpack@7.1.1", "", { "dependencies": { "dotenv-defaults": "^2.0.2" }, "peerDependencies": { "webpack": "^4 || ^5" } }, "sha512-xw/19VqHDkXALtBOJAnnrSU/AZDIQRXczAmJyp0lZv6SH2aBLzUTl96W1MVryJZ7okZ+djZS4Gj4KlZ0xP7deA=="],
"drizzle-kit": ["drizzle-kit@0.31.8", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-O9EC/miwdnRDY10qRxM8P3Pg8hXe3LyU4ZipReKOgTwn4OqANmftj8XJz1UPUAS6NMHf0E2htjsbQujUTkncCg=="],
"drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
@ -1946,6 +1960,8 @@
"esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"escape-goat": ["escape-goat@3.0.0", "", {}, "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw=="], "escape-goat": ["escape-goat@3.0.0", "", {}, "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw=="],
@ -3622,6 +3638,8 @@
"@csstools/selector-specificity/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], "@csstools/selector-specificity/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"@eslint/eslintrc/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], "@eslint/eslintrc/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"@hapi/boom/@hapi/hoek": ["@hapi/hoek@11.0.7", "", {}, "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ=="], "@hapi/boom/@hapi/hoek": ["@hapi/hoek@11.0.7", "", {}, "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ=="],
@ -4304,6 +4322,50 @@
"@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
"@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"@humanwhocodes/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "@humanwhocodes/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],

View File

@ -0,0 +1,17 @@
import 'dotenv/config'
import { defineConfig } from 'drizzle-kit'
import { CONFIG } from './src/config'
export default defineConfig({
out: './drizzle',
schema: './src/schemas/drizzle.schema.ts',
dialect: 'mysql',
dbCredentials: {
// url: process.env.DATABASE_URL!,
host: CONFIG.DB_HOST,
user: CONFIG.DB_USER,
password: CONFIG.DB_PASSWORD.length > 0 ? CONFIG.DB_PASSWORD : undefined,
database: CONFIG.DB_DATABASE,
port: CONFIG.DB_PORT,
},
})

View File

@ -37,6 +37,7 @@
"@types/geojson": "^7946.0.13", "@types/geojson": "^7946.0.13",
"@types/mysql": "^2.15.27", "@types/mysql": "^2.15.27",
"@types/node": "^18.7.14", "@types/node": "^18.7.14",
"drizzle-kit": "^0.31.7",
"random-bigint": "^0.0.1", "random-bigint": "^0.0.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^4.9.5" "typescript": "^4.9.5"
@ -46,6 +47,7 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"decimal.js-light": "^2.5.1", "decimal.js-light": "^2.5.1",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"drizzle-orm": "^0.44.7",
"esbuild": "^0.25.2", "esbuild": "^0.25.2",
"geojson": "^0.5.0", "geojson": "^0.5.0",
"ioredis": "^5.8.2", "ioredis": "^5.8.2",

View File

@ -1,5 +1,7 @@
import { drizzle, MySql2Database } from 'drizzle-orm/mysql2'
import Redis from 'ioredis' import Redis from 'ioredis'
import { getLogger } from 'log4js' import { getLogger } from 'log4js'
import { Connection, createConnection } from 'mysql2/promise'
import { DataSource as DBDataSource, FileLogger } from 'typeorm' import { DataSource as DBDataSource, FileLogger } from 'typeorm'
import { latestDbVersion } from '.' import { latestDbVersion } from '.'
import { CONFIG } from './config' import { CONFIG } from './config'
@ -11,6 +13,8 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.AppDatabase`)
export class AppDatabase { export class AppDatabase {
private static instance: AppDatabase private static instance: AppDatabase
private dataSource: DBDataSource | undefined private dataSource: DBDataSource | undefined
private drizzleDataSource: MySql2Database | undefined
private drizzleConnection: Connection | undefined
private redisClient: Redis | undefined private redisClient: Redis | undefined
/** /**
@ -43,6 +47,13 @@ export class AppDatabase {
return this.dataSource return this.dataSource
} }
public getDrizzleDataSource(): MySql2Database {
if (!this.drizzleDataSource) {
throw new Error('Drizzle connection not initialized')
}
return this.drizzleDataSource
}
// create database connection, initialize with automatic retry and check for correct database version // create database connection, initialize with automatic retry and check for correct database version
public async init(): Promise<void> { public async init(): Promise<void> {
if (this.dataSource?.isInitialized) { if (this.dataSource?.isInitialized) {
@ -71,6 +82,7 @@ export class AppDatabase {
}, },
}) })
} }
// retry connection on failure some times to allow database to catch up // retry connection on failure some times to allow database to catch up
for (let attempt = 1; attempt <= CONFIG.DB_CONNECT_RETRY_COUNT; attempt++) { for (let attempt = 1; attempt <= CONFIG.DB_CONNECT_RETRY_COUNT; attempt++) {
try { try {
@ -92,10 +104,24 @@ export class AppDatabase {
this.redisClient = new Redis(CONFIG.REDIS_URL) this.redisClient = new Redis(CONFIG.REDIS_URL)
logger.info('Redis status=', this.redisClient.status) logger.info('Redis status=', this.redisClient.status)
if (!this.drizzleDataSource) {
this.drizzleConnection = await createConnection({
host: CONFIG.DB_HOST,
user: CONFIG.DB_USER,
password: CONFIG.DB_PASSWORD,
database: CONFIG.DB_DATABASE,
port: CONFIG.DB_PORT,
})
this.drizzleDataSource = drizzle({ client: this.drizzleConnection })
}
} }
public async destroy(): Promise<void> { public async destroy(): Promise<void> {
await this.dataSource?.destroy() await Promise.all([this.dataSource?.destroy(), this.drizzleConnection?.end()])
this.dataSource = undefined
this.drizzleConnection = undefined
this.drizzleDataSource = undefined
if (this.redisClient) { if (this.redisClient) {
await this.redisClient.quit() await this.redisClient.quit()
this.redisClient = undefined this.redisClient = undefined
@ -128,3 +154,4 @@ export class AppDatabase {
} }
export const getDataSource = () => AppDatabase.getInstance().getDataSource() export const getDataSource = () => AppDatabase.getInstance().getDataSource()
export const drizzleDb = () => AppDatabase.getInstance().getDrizzleDataSource()

View File

@ -13,7 +13,7 @@ const database = {
DB_CONNECT_RETRY_DELAY_MS: process.env.DB_CONNECT_RETRY_DELAY_MS DB_CONNECT_RETRY_DELAY_MS: process.env.DB_CONNECT_RETRY_DELAY_MS
? Number.parseInt(process.env.DB_CONNECT_RETRY_DELAY_MS) ? Number.parseInt(process.env.DB_CONNECT_RETRY_DELAY_MS)
: 500, : 500,
DB_HOST: process.env.DB_HOST ?? 'localhost', DB_HOST: process.env.DB_HOST ?? '127.0.0.1',
DB_PORT: process.env.DB_PORT ? Number.parseInt(process.env.DB_PORT) : 3306, DB_PORT: process.env.DB_PORT ? Number.parseInt(process.env.DB_PORT) : 3306,
DB_USER: process.env.DB_USER ?? 'root', DB_USER: process.env.DB_USER ?? 'root',
DB_PASSWORD: process.env.DB_PASSWORD ?? '', DB_PASSWORD: process.env.DB_PASSWORD ?? '',

View File

@ -1,23 +0,0 @@
import {
BaseEntity,
Column,
CreateDateColumn,
Entity,
PrimaryColumn,
UpdateDateColumn,
} from 'typeorm'
@Entity('openai_threads')
export class OpenaiThreads extends BaseEntity {
@PrimaryColumn({ type: 'char', length: 30 })
id: string
@CreateDateColumn({ type: 'timestamp' })
createdAt: Date
@UpdateDateColumn({ type: 'timestamp' })
updatedAt: Date
@Column({ name: 'user_id', type: 'int', unsigned: true })
userId: number
}

View File

@ -8,7 +8,6 @@ import { Event } from './Event'
import { FederatedCommunity } from './FederatedCommunity' import { FederatedCommunity } from './FederatedCommunity'
import { LoginElopageBuys } from './LoginElopageBuys' import { LoginElopageBuys } from './LoginElopageBuys'
import { Migration } from './Migration' import { Migration } from './Migration'
import { OpenaiThreads } from './OpenaiThreads'
import { PendingTransaction } from './PendingTransaction' import { PendingTransaction } from './PendingTransaction'
import { ProjectBranding } from './ProjectBranding' import { ProjectBranding } from './ProjectBranding'
import { Transaction } from './Transaction' import { Transaction } from './Transaction'
@ -29,7 +28,6 @@ export {
LoginElopageBuys, LoginElopageBuys,
Migration, Migration,
ProjectBranding, ProjectBranding,
OpenaiThreads,
PendingTransaction, PendingTransaction,
Transaction, Transaction,
TransactionLink, TransactionLink,
@ -50,7 +48,6 @@ export const entities = [
LoginElopageBuys, LoginElopageBuys,
Migration, Migration,
ProjectBranding, ProjectBranding,
OpenaiThreads,
PendingTransaction, PendingTransaction,
Transaction, Transaction,
TransactionLink, TransactionLink,

View File

@ -6,4 +6,5 @@ export * from './entity'
export * from './enum' export * from './enum'
export * from './logging' export * from './logging'
export * from './queries' export * from './queries'
export * from './schemas'
export * from './seeds' export * from './seeds'

View File

@ -3,6 +3,7 @@ import { LOG4JS_BASE_CATEGORY_NAME } from '../config/const'
export * from './communities' export * from './communities'
export * from './communityHandshakes' export * from './communityHandshakes'
export * from './events' export * from './events'
export * from './openaiThreads'
export * from './pendingTransactions' export * from './pendingTransactions'
export * from './transactionLinks' export * from './transactionLinks'
export * from './transactions' export * from './transactions'

View File

@ -0,0 +1,70 @@
import { eq } from 'drizzle-orm'
import { MySql2Database } from 'drizzle-orm/mysql2'
import { AppDatabase, drizzleDb } from '../AppDatabase'
import { openaiThreadsTable } from '../schemas'
import {
dbDeleteOpenaiThread,
dbFindNewestCreatedOpenaiThreadByUserId,
dbInsertOpenaiThread,
dbUpdateOpenaiThread,
} from './openaiThreads'
const appDB = AppDatabase.getInstance()
let db: MySql2Database
beforeAll(async () => {
await appDB.init()
db = drizzleDb()
await db.delete(openaiThreadsTable)
})
afterAll(async () => {
await appDB.destroy()
})
describe('openaiThreads query test', () => {
it('should insert a new openai thread', async () => {
await Promise.resolve([dbInsertOpenaiThread('7', 1), dbInsertOpenaiThread('72', 6)])
const result = await db.select().from(openaiThreadsTable)
expect(result).toHaveLength(2)
expect(result).toMatchObject([
{ id: '7', userId: 1 },
{ id: '72', userId: 6 },
])
})
it('should find the newest created openai thread by user id', async () => {
await db.insert(openaiThreadsTable).values([
{ id: '75', userId: 2, createdAt: new Date('2025-01-01T00:00:00.000Z') },
{ id: '172', userId: 2, createdAt: new Date('2025-01-02T00:00:00.000Z') },
])
const result = await dbFindNewestCreatedOpenaiThreadByUserId(2)
expect(result).toBeDefined()
expect(result).toMatchObject({
id: '172',
userId: 2,
createdAt: new Date('2025-01-02T00:00:00.000Z'),
})
})
it('should update an existing openai thread', async () => {
const now = new Date()
now.setMilliseconds(0)
await dbUpdateOpenaiThread('172')
const result = await db
.select()
.from(openaiThreadsTable)
.where(eq(openaiThreadsTable.id, '172'))
expect(result).toHaveLength(1)
expect(result[0].updatedAt.getTime()).toBeGreaterThanOrEqual(now.getTime())
expect(result).toMatchObject([{ id: '172', userId: 2, updatedAt: expect.any(Date) }])
})
it('should delete an existing openai thread', async () => {
await dbDeleteOpenaiThread('172')
const result = await db
.select()
.from(openaiThreadsTable)
.where(eq(openaiThreadsTable.id, '172'))
expect(result).toHaveLength(0)
})
})

View File

@ -0,0 +1,32 @@
import { desc, eq } from 'drizzle-orm'
import { drizzleDb } from '../AppDatabase'
import { openaiThreadsTable } from '../schemas/drizzle.schema'
// TODO: replace results with valibot schema after update to typescript 5 is possible
export async function dbInsertOpenaiThread(id: string, userId: number): Promise<void> {
await drizzleDb().insert(openaiThreadsTable).values({ id, userId })
}
export async function dbUpdateOpenaiThread(id: string): Promise<void> {
await drizzleDb()
.update(openaiThreadsTable)
.set({ updatedAt: new Date() })
.where(eq(openaiThreadsTable.id, id))
}
export async function dbFindNewestCreatedOpenaiThreadByUserId(
userId: number,
): Promise<typeof openaiThreadsTable.$inferSelect | undefined> {
const result = await drizzleDb()
.select()
.from(openaiThreadsTable)
.where(eq(openaiThreadsTable.userId, userId))
.orderBy(desc(openaiThreadsTable.createdAt))
.limit(1)
return result.at(0)
}
export async function dbDeleteOpenaiThread(id: string): Promise<void> {
await drizzleDb().delete(openaiThreadsTable).where(eq(openaiThreadsTable.id, id))
}

View File

@ -0,0 +1,8 @@
import { int, mysqlTable, timestamp, varchar } from 'drizzle-orm/mysql-core'
export const openaiThreadsTable = mysqlTable('openai_threads', {
id: varchar({ length: 128 }).notNull(),
createdAt: timestamp({ mode: 'date' }).defaultNow().notNull(),
updatedAt: timestamp({ mode: 'date' }).defaultNow().onUpdateNow().notNull(),
userId: int('user_id').notNull(),
})

View File

@ -0,0 +1 @@
export * from './drizzle.schema'

View File

@ -19,4 +19,7 @@ module.exports = {
transform: { transform: {
'^.+\\.(t|j)sx?$': '@swc/jest', '^.+\\.(t|j)sx?$': '@swc/jest',
}, },
transformIgnorePatterns: [
'/node_modules/(?!drizzle-orm/)',
],
} }

View File

@ -1,7 +1,11 @@
import DHT from '@hyperswarm/dht' import DHT from '@hyperswarm/dht'
import { cleanDB, testEnvironment } from '@test/helpers' import { cleanDB, testEnvironment } from '@test/helpers'
import { getLogger } from 'config-schema/test/testSetup' import { getLogger } from 'config-schema/test/testSetup'
import { Community as DbCommunity, FederatedCommunity as DbFederatedCommunity } from 'database' import {
AppDatabase,
Community as DbCommunity,
FederatedCommunity as DbFederatedCommunity,
} from 'database'
import { validate as validateUUID, version as versionUUID } from 'uuid' import { validate as validateUUID, version as versionUUID } from 'uuid'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
@ -94,18 +98,18 @@ DHT.mockImplementation(() => {
} }
}) })
let con: any let db: AppDatabase
let testEnv: any let testEnv: any
beforeAll(async () => { beforeAll(async () => {
testEnv = await testEnvironment() testEnv = await testEnvironment()
con = testEnv.con db = testEnv.db
await cleanDB() await cleanDB()
}) })
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
await con.close() await db.destroy()
}) })
describe('federation', () => { describe('federation', () => {

View File

@ -25,7 +25,7 @@ export const cleanDB = async () => {
export const testEnvironment = async () => { export const testEnvironment = async () => {
const appDB = AppDatabase.getInstance() const appDB = AppDatabase.getInstance()
await appDB.init() await appDB.init()
return { con: appDB.getDataSource() } return { con: appDB.getDataSource(), db: appDB }
} }
export const resetEntity = async (entity: any) => { export const resetEntity = async (entity: any) => {

View File

@ -20,21 +20,22 @@ module.exports = {
'@union/(.*)': '<rootDir>/src/graphql/union/$1', '@union/(.*)': '<rootDir>/src/graphql/union/$1',
'@repository/(.*)': '<rootDir>/src/typeorm/repository/$1', '@repository/(.*)': '<rootDir>/src/typeorm/repository/$1',
'@test/(.*)': '<rootDir>/test/$1', '@test/(.*)': '<rootDir>/test/$1',
'@entity/(.*)':
process.env.NODE_ENV === 'development'
? '<rootDir>/../database/entity/$1'
: '<rootDir>/../database/build/entity/$1',
'@logging/(.*)':
process.env.NODE_ENV === 'development'
? '<rootDir>/../database/logging/$1'
: '<rootDir>/../database/build/logging/$1',
'@dbTools/(.*)':
process.env.NODE_ENV === 'development'
? '<rootDir>/../database/src/$1'
: '<rootDir>/../database/build/src/$1',
'@config/(.*)':
process.env.NODE_ENV === 'development'
? '<rootDir>/../config/src/$1'
: '<rootDir>/../config/build/$1',
}, },
transform: {
'^.+\\.(t|j)sx?$': ['@swc/jest', {
jsc: {
parser: {
syntax: 'typescript',
decorators: true,
tsc: true,
},
transform: {
decoratorMetadata: true,
},
}
}],
},
transformIgnorePatterns: [
'/node_modules/(?!drizzle-orm/)',
],
} }

View File

@ -33,6 +33,7 @@
"@swc/cli": "^0.7.3", "@swc/cli": "^0.7.3",
"@swc/core": "^1.11.24", "@swc/core": "^1.11.24",
"@swc/helpers": "^0.5.17", "@swc/helpers": "^0.5.17",
"@swc/jest": "^0.2.38",
"@types/cors": "^2.8.19", "@types/cors": "^2.8.19",
"@types/express": "4.17.21", "@types/express": "4.17.21",
"@types/jest": "27.0.2", "@types/jest": "27.0.2",

View File

@ -1,26 +1,21 @@
import { createTestClient } from 'apollo-server-testing' import { createTestClient } from 'apollo-server-testing'
import { Community as DbCommunity } from 'database' import { AppDatabase, Community as DbCommunity } from 'database'
import { getLogger } from 'log4js' import { getLogger } from 'log4js'
import { DataSource } from 'typeorm'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { createServer } from '@/server/createServer' import { createServer } from '@/server/createServer'
let query: any let query: any
// to do: We need a setup for the tests that closes the connection
let con: DataSource
CONFIG.FEDERATION_API = '1_0' CONFIG.FEDERATION_API = '1_0'
beforeAll(async () => { beforeAll(async () => {
const server = await createServer(getLogger('apollo')) const server = await createServer(getLogger('apollo'))
con = server.con
query = createTestClient(server.apollo).query query = createTestClient(server.apollo).query
DbCommunity.clear() DbCommunity.clear()
}) })
afterAll(async () => { afterAll(async () => {
await con.close() await AppDatabase.getInstance().destroy()
}) })
describe('PublicCommunityInfoResolver', () => { describe('PublicCommunityInfoResolver', () => {

View File

@ -1,26 +1,23 @@
import { createTestClient } from 'apollo-server-testing' import { createTestClient } from 'apollo-server-testing'
import { FederatedCommunity as DbFederatedCommunity } from 'database' import { AppDatabase, FederatedCommunity as DbFederatedCommunity } from 'database'
import { getLogger } from 'log4js' import { getLogger } from 'log4js'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { createServer } from '@/server/createServer' import { createServer } from '@/server/createServer'
let query: any let query: any
// to do: We need a setup for the tests that closes the connection // to do: We need a setup for the tests that closes the connection
let con: any
CONFIG.FEDERATION_API = '1_0' CONFIG.FEDERATION_API = '1_0'
beforeAll(async () => { beforeAll(async () => {
const server = await createServer(getLogger('apollo')) const server = await createServer(getLogger('apollo'))
con = server.con
query = createTestClient(server.apollo).query query = createTestClient(server.apollo).query
DbFederatedCommunity.clear() DbFederatedCommunity.clear()
}) })
afterAll(async () => { afterAll(async () => {
await con.close() await AppDatabase.getInstance().destroy()
}) })
describe('PublicKeyResolver', () => { describe('PublicKeyResolver', () => {

View File

@ -1,7 +1,12 @@
import { cleanDB, testEnvironment } from '@test/helpers' import { cleanDB, testEnvironment } from '@test/helpers'
import { ApolloServerTestClient } from 'apollo-server-testing' import { ApolloServerTestClient } from 'apollo-server-testing'
import { EncryptedTransferArgs } from 'core' import { EncryptedTransferArgs } from 'core'
import { Community as DbCommunity, User as DbUser, UserContact as DbUserContact } from 'database' import {
AppDatabase,
Community as DbCommunity,
User as DbUser,
UserContact as DbUserContact,
} from 'database'
import Decimal from 'decimal.js-light' import Decimal from 'decimal.js-light'
import { GraphQLError } from 'graphql' import { GraphQLError } from 'graphql'
import { getLogger } from 'log4js' import { getLogger } from 'log4js'
@ -14,7 +19,6 @@ import {
} from 'shared' } from 'shared'
import { DataSource } from 'typeorm' import { DataSource } from 'typeorm'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
import { fullName } from '@/graphql/util/fullName' import { fullName } from '@/graphql/util/fullName'
let mutate: ApolloServerTestClient['mutate'] // , con: Connection let mutate: ApolloServerTestClient['mutate'] // , con: Connection
@ -46,7 +50,7 @@ beforeAll(async () => {
afterAll(async () => { afterAll(async () => {
await cleanDB() await cleanDB()
if (testEnv.con?.isInitialized) { if (testEnv.con?.isInitialized) {
await testEnv.con.destroy() await AppDatabase.getInstance().destroy()
} }
}) })

View File

@ -1,5 +1,5 @@
import { createTestClient } from 'apollo-server-testing' import { createTestClient } from 'apollo-server-testing'
import { FederatedCommunity as DbFederatedCommunity } from 'database' import { AppDatabase, FederatedCommunity as DbFederatedCommunity } from 'database'
import { getLogger } from 'log4js' import { getLogger } from 'log4js'
import { CONFIG } from '@/config' import { CONFIG } from '@/config'
import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const'
@ -8,19 +8,17 @@ import { createServer } from '@/server/createServer'
let query: any let query: any
// to do: We need a setup for the tests that closes the connection // to do: We need a setup for the tests that closes the connection
let con: any
CONFIG.FEDERATION_API = '1_1' CONFIG.FEDERATION_API = '1_1'
beforeAll(async () => { beforeAll(async () => {
const server = await createServer(getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apollo`)) const server = await createServer(getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.apollo`))
con = server.con
query = createTestClient(server.apollo).query query = createTestClient(server.apollo).query
DbFederatedCommunity.clear() DbFederatedCommunity.clear()
}) })
afterAll(async () => { afterAll(async () => {
await con.close() await AppDatabase.getInstance().destroy()
}) })
describe('PublicKeyResolver', () => { describe('PublicKeyResolver', () => {