feat: refactor Prisma client initialization and update related services
This commit is contained in:
+4
-1
@@ -1,7 +1,10 @@
|
||||
import { PasswordUtil } from '@/common/utils/password.util'
|
||||
import { GoodPricingModel } from '@/generated/prisma/enums'
|
||||
import { GoodCreateManyInput } from '@/generated/prisma/models'
|
||||
import { prisma } from '../src/lib/prisma'
|
||||
import { PrismaClient } from '../src/generated/prisma/client'
|
||||
import { prismaAdapter } from '../src/lib/prisma'
|
||||
|
||||
const prisma = new PrismaClient({ adapter: prismaAdapter })
|
||||
|
||||
async function main() {
|
||||
const password = await PasswordUtil.hash('123456')
|
||||
|
||||
@@ -1,66 +1,65 @@
|
||||
#!/usr/bin/env ts-node
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { prisma } from '../src/lib/prisma'
|
||||
// #!/usr/bin/env ts-node
|
||||
// import * as fs from 'fs'
|
||||
// import * as path from 'path'
|
||||
|
||||
function findModules(dir: string): string[] {
|
||||
const results: string[] = []
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||
for (const e of entries) {
|
||||
const full = path.join(dir, e.name)
|
||||
if (e.isDirectory()) {
|
||||
results.push(...findModules(full))
|
||||
} else if (e.isFile() && e.name.endsWith('.module.ts')) {
|
||||
results.push(full)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
function moduleNameFromFile(filePath: string) {
|
||||
const name = path.basename(filePath).replace('.module.ts', '')
|
||||
return name.replace(/-module$|\.module$/i, '')
|
||||
}
|
||||
|
||||
function makePermissionsFor(moduleName: string) {
|
||||
const base = moduleName.replace(/\W+/g, '_').toLowerCase()
|
||||
return [`${base}:create`, `${base}:read`, `${base}:update`, `${base}:delete`]
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// const srcDir = path.resolve(__dirname, '..', 'src')
|
||||
// const moduleFiles = findModules(srcDir)
|
||||
// const modules = moduleFiles.map(moduleNameFromFile)
|
||||
|
||||
// const permsMap: Record<string, boolean> = {}
|
||||
// for (const m of modules) {
|
||||
// for (const p of makePermissionsFor(m)) permsMap[p] = false
|
||||
// function findModules(dir: string): string[] {
|
||||
// const results: string[] = []
|
||||
// const entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||
// for (const e of entries) {
|
||||
// const full = path.join(dir, e.name)
|
||||
// if (e.isDirectory()) {
|
||||
// results.push(...findModules(full))
|
||||
// } else if (e.isFile() && e.name.endsWith('.module.ts')) {
|
||||
// results.push(full)
|
||||
// }
|
||||
// }
|
||||
// return results
|
||||
// }
|
||||
|
||||
// // Upsert roles: ensure admin has full permissions, others get entries added
|
||||
// const roles = await prisma.role.findMany()
|
||||
// for (const r of roles) {
|
||||
// const current: Record<string, any> = (r.permissions as any) || {}
|
||||
// const merged = { ...permsMap, ...current }
|
||||
|
||||
// // If role name is admin (case-insensitive), set all permissions to true
|
||||
// if (r.name && r.name.toLowerCase() === 'admin') {
|
||||
// for (const key of Object.keys(merged)) merged[key] = true
|
||||
// } else {
|
||||
// // keep existing truthy values, otherwise false
|
||||
// for (const key of Object.keys(merged)) merged[key] = merged[key] || false
|
||||
// function moduleNameFromFile(filePath: string) {
|
||||
// const name = path.basename(filePath).replace('.module.ts', '')
|
||||
// return name.replace(/-module$|\.module$/i, '')
|
||||
// }
|
||||
|
||||
// await prisma.role.update({ where: { id: r.id }, data: { permissions: merged } })
|
||||
// console.log(
|
||||
// `Updated role ${r.name} (id=${r.id}) with ${Object.keys(merged).length} permissions`,
|
||||
// )
|
||||
// function makePermissionsFor(moduleName: string) {
|
||||
// const base = moduleName.replace(/\W+/g, '_').toLowerCase()
|
||||
// return [`${base}:create`, `${base}:read`, `${base}:update`, `${base}:delete`]
|
||||
// }
|
||||
|
||||
await prisma.$disconnect()
|
||||
}
|
||||
// async function main() {
|
||||
// // const srcDir = path.resolve(__dirname, '..', 'src')
|
||||
// // const moduleFiles = findModules(srcDir)
|
||||
// // const modules = moduleFiles.map(moduleNameFromFile)
|
||||
|
||||
main().catch(e => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
||||
// // const permsMap: Record<string, boolean> = {}
|
||||
// // for (const m of modules) {
|
||||
// // for (const p of makePermissionsFor(m)) permsMap[p] = false
|
||||
// // }
|
||||
|
||||
// // // Upsert roles: ensure admin has full permissions, others get entries added
|
||||
// // const roles = await prisma.role.findMany()
|
||||
// // for (const r of roles) {
|
||||
// // const current: Record<string, any> = (r.permissions as any) || {}
|
||||
// // const merged = { ...permsMap, ...current }
|
||||
|
||||
// // // If role name is admin (case-insensitive), set all permissions to true
|
||||
// // if (r.name && r.name.toLowerCase() === 'admin') {
|
||||
// // for (const key of Object.keys(merged)) merged[key] = true
|
||||
// // } else {
|
||||
// // // keep existing truthy values, otherwise false
|
||||
// // for (const key of Object.keys(merged)) merged[key] = merged[key] || false
|
||||
// // }
|
||||
|
||||
// // await prisma.role.update({ where: { id: r.id }, data: { permissions: merged } })
|
||||
// // console.log(
|
||||
// // `Updated role ${r.name} (id=${r.id}) with ${Object.keys(merged).length} permissions`,
|
||||
// // )
|
||||
// // }
|
||||
|
||||
// await prisma.$disconnect()
|
||||
// }
|
||||
|
||||
// main().catch(e => {
|
||||
// console.error(e)
|
||||
// process.exit(1)
|
||||
// })
|
||||
|
||||
+121
-122
@@ -1,144 +1,143 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { prisma } from '../src/lib/prisma'
|
||||
// import fs from 'node:fs'
|
||||
// import path from 'node:path'
|
||||
|
||||
type CsvRow = {
|
||||
ID?: string
|
||||
DescriptionOfID?: string
|
||||
Vat?: string
|
||||
Type?: string
|
||||
}
|
||||
// type CsvRow = {
|
||||
// ID?: string
|
||||
// DescriptionOfID?: string
|
||||
// Vat?: string
|
||||
// Type?: string
|
||||
// }
|
||||
|
||||
function parseCsvLine(line: string): string[] {
|
||||
const result: string[] = []
|
||||
let current = ''
|
||||
let inQuotes = false
|
||||
// function parseCsvLine(line: string): string[] {
|
||||
// const result: string[] = []
|
||||
// let current = ''
|
||||
// let inQuotes = false
|
||||
|
||||
for (let index = 0; index < line.length; index++) {
|
||||
const char = line[index]
|
||||
// for (let index = 0; index < line.length; index++) {
|
||||
// const char = line[index]
|
||||
|
||||
if (char === '"') {
|
||||
if (inQuotes && line[index + 1] === '"') {
|
||||
current += '"'
|
||||
index++
|
||||
} else {
|
||||
inQuotes = !inQuotes
|
||||
}
|
||||
continue
|
||||
}
|
||||
// if (char === '"') {
|
||||
// if (inQuotes && line[index + 1] === '"') {
|
||||
// current += '"'
|
||||
// index++
|
||||
// } else {
|
||||
// inQuotes = !inQuotes
|
||||
// }
|
||||
// continue
|
||||
// }
|
||||
|
||||
if (char === ',' && !inQuotes) {
|
||||
result.push(current)
|
||||
current = ''
|
||||
continue
|
||||
}
|
||||
// if (char === ',' && !inQuotes) {
|
||||
// result.push(current)
|
||||
// current = ''
|
||||
// continue
|
||||
// }
|
||||
|
||||
current += char
|
||||
}
|
||||
// current += char
|
||||
// }
|
||||
|
||||
result.push(current)
|
||||
return result.map(value => value.trim())
|
||||
}
|
||||
// result.push(current)
|
||||
// return result.map(value => value.trim())
|
||||
// }
|
||||
|
||||
function parseCsv(content: string): CsvRow[] {
|
||||
const lines = content
|
||||
.split(/\r?\n/)
|
||||
.map(line => line.trim())
|
||||
.filter(Boolean)
|
||||
// function parseCsv(content: string): CsvRow[] {
|
||||
// const lines = content
|
||||
// .split(/\r?\n/)
|
||||
// .map(line => line.trim())
|
||||
// .filter(Boolean)
|
||||
|
||||
if (!lines.length) return []
|
||||
// if (!lines.length) return []
|
||||
|
||||
const headers = parseCsvLine(lines[0])
|
||||
return lines.slice(1).map(line => {
|
||||
const cols = parseCsvLine(line)
|
||||
const row: Record<string, string> = {}
|
||||
for (let index = 0; index < headers.length; index++) {
|
||||
row[headers[index]] = cols[index] || ''
|
||||
}
|
||||
return row
|
||||
})
|
||||
}
|
||||
// const headers = parseCsvLine(lines[0])
|
||||
// return lines.slice(1).map(line => {
|
||||
// const cols = parseCsvLine(line)
|
||||
// const row: Record<string, string> = {}
|
||||
// for (let index = 0; index < headers.length; index++) {
|
||||
// row[headers[index]] = cols[index] || ''
|
||||
// }
|
||||
// return row
|
||||
// })
|
||||
// }
|
||||
|
||||
function toBooleanFlags(typeValue: string) {
|
||||
const normalized = typeValue || ''
|
||||
const isPublic = normalized.includes('شناسه عمومی')
|
||||
const isImported = normalized.includes('وارداتی')
|
||||
const isDomestic = !isImported
|
||||
// function toBooleanFlags(typeValue: string) {
|
||||
// const normalized = typeValue || ''
|
||||
// const isPublic = normalized.includes('شناسه عمومی')
|
||||
// const isImported = normalized.includes('وارداتی')
|
||||
// const isDomestic = !isImported
|
||||
|
||||
return { isPublic, isDomestic }
|
||||
}
|
||||
// return { isPublic, isDomestic }
|
||||
// }
|
||||
|
||||
function parseVat(vatValue: string) {
|
||||
const parsed = Number(vatValue || '0')
|
||||
if (!Number.isFinite(parsed)) return 0
|
||||
return parsed
|
||||
}
|
||||
// function parseVat(vatValue: string) {
|
||||
// const parsed = Number(vatValue || '0')
|
||||
// if (!Number.isFinite(parsed)) return 0
|
||||
// return parsed
|
||||
// }
|
||||
|
||||
async function main() {
|
||||
const defaultPath =
|
||||
'/Users/ahasani/Desktop/product_good_2026-05-01T11-35-57_part_1_28812448-0dd9-411c-99e1-334c28d781fe.csv'
|
||||
const csvPath = process.argv[2] || defaultPath
|
||||
const absolutePath = path.resolve(csvPath)
|
||||
// async function main() {
|
||||
// const defaultPath =
|
||||
// '/Users/ahasani/Desktop/product_good_2026-05-01T11-35-57_part_1_28812448-0dd9-411c-99e1-334c28d781fe.csv'
|
||||
// const csvPath = process.argv[2] || defaultPath
|
||||
// const absolutePath = path.resolve(csvPath)
|
||||
|
||||
if (!fs.existsSync(absolutePath)) {
|
||||
throw new Error(`CSV file not found: ${absolutePath}`)
|
||||
}
|
||||
// if (!fs.existsSync(absolutePath)) {
|
||||
// throw new Error(`CSV file not found: ${absolutePath}`)
|
||||
// }
|
||||
|
||||
const raw = fs.readFileSync(absolutePath, 'utf8').replace(/^\uFEFF/, '')
|
||||
const rows = parseCsv(raw)
|
||||
// const raw = fs.readFileSync(absolutePath, 'utf8').replace(/^\uFEFF/, '')
|
||||
// const rows = parseCsv(raw)
|
||||
|
||||
let upserted = 0
|
||||
let skipped = 0
|
||||
// let upserted = 0
|
||||
// let skipped = 0
|
||||
|
||||
const guild = await prisma.guild.findFirst({})
|
||||
// const guild = await prisma.guild.findFirst({})
|
||||
|
||||
for (const row of rows) {
|
||||
const code = (row.ID || '').trim()
|
||||
const name = (row.DescriptionOfID || '').trim()
|
||||
const vat = parseVat((row.Vat || '').trim())
|
||||
const type = (row.Type || '').trim()
|
||||
const { isPublic, isDomestic } = toBooleanFlags(type)
|
||||
// for (const row of rows) {
|
||||
// const code = (row.ID || '').trim()
|
||||
// const name = (row.DescriptionOfID || '').trim()
|
||||
// const vat = parseVat((row.Vat || '').trim())
|
||||
// const type = (row.Type || '').trim()
|
||||
// const { isPublic, isDomestic } = toBooleanFlags(type)
|
||||
|
||||
if (!code || !name) {
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
// if (!code || !name) {
|
||||
// skipped++
|
||||
// continue
|
||||
// }
|
||||
|
||||
await prisma.stockKeepingUnits.upsert({
|
||||
where: { code },
|
||||
create: {
|
||||
code,
|
||||
name,
|
||||
VAT: vat,
|
||||
guild: {
|
||||
connect: {
|
||||
id: guild?.id,
|
||||
},
|
||||
},
|
||||
is_public: isPublic,
|
||||
is_domestic: isDomestic,
|
||||
},
|
||||
update: {
|
||||
name,
|
||||
VAT: vat,
|
||||
guild: {
|
||||
connect: {
|
||||
id: guild?.id,
|
||||
},
|
||||
},
|
||||
is_public: isPublic,
|
||||
is_domestic: isDomestic,
|
||||
},
|
||||
})
|
||||
upserted++
|
||||
}
|
||||
}
|
||||
// await prisma.stockKeepingUnits.upsert({
|
||||
// where: { code },
|
||||
// create: {
|
||||
// code,
|
||||
// name,
|
||||
// VAT: vat,
|
||||
// guild: {
|
||||
// connect: {
|
||||
// id: guild?.id,
|
||||
// },
|
||||
// },
|
||||
// is_public: isPublic,
|
||||
// is_domestic: isDomestic,
|
||||
// },
|
||||
// update: {
|
||||
// name,
|
||||
// VAT: vat,
|
||||
// guild: {
|
||||
// connect: {
|
||||
// id: guild?.id,
|
||||
// },
|
||||
// },
|
||||
// is_public: isPublic,
|
||||
// is_domestic: isDomestic,
|
||||
// },
|
||||
// })
|
||||
// upserted++
|
||||
// }
|
||||
// }
|
||||
|
||||
main()
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
// main()
|
||||
// .catch(error => {
|
||||
// console.error(error)
|
||||
// process.exit(1)
|
||||
// })
|
||||
// .finally(async () => {
|
||||
// await prisma.$disconnect()
|
||||
// })
|
||||
|
||||
+2
-4
@@ -2,8 +2,6 @@ import { PrismaMariaDb } from '@prisma/adapter-mariadb'
|
||||
import 'dotenv/config'
|
||||
import { env } from 'prisma/config'
|
||||
|
||||
import { PrismaClient } from '../generated/prisma/client'
|
||||
|
||||
const adapter = new PrismaMariaDb({
|
||||
host: env('DATABASE_HOST'),
|
||||
user: env('DATABASE_USER'),
|
||||
@@ -18,6 +16,6 @@ const adapter = new PrismaMariaDb({
|
||||
connectTimeout: 10000,
|
||||
})
|
||||
|
||||
const prisma = new PrismaClient({ adapter })
|
||||
// const prisma = new PrismaClient({ adapter })
|
||||
|
||||
export { prisma }
|
||||
export { adapter as prismaAdapter }
|
||||
|
||||
@@ -17,6 +17,8 @@ const cookieParser = require('cookie-parser')
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule)
|
||||
|
||||
app.enableShutdownHooks()
|
||||
|
||||
app.use(cookieParser())
|
||||
|
||||
const config = new DocumentBuilder()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { SKUGuildType } from '@/common/enums/enums'
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
|
||||
import { Type } from 'class-transformer'
|
||||
import { IsBoolean, IsEnum, IsNumber, IsString, Min } from 'class-validator'
|
||||
import { IsBoolean, IsNumber, IsString, Min } from 'class-validator'
|
||||
|
||||
export class CreateStockKeepingUnitDto {
|
||||
@ApiProperty()
|
||||
@@ -18,9 +17,9 @@ export class CreateStockKeepingUnitDto {
|
||||
@Min(0)
|
||||
VAT: number
|
||||
|
||||
@ApiPropertyOptional({ enum: SKUGuildType, default: SKUGuildType.GOLD })
|
||||
@IsEnum(SKUGuildType)
|
||||
type: SKUGuildType = SKUGuildType.GOLD
|
||||
// @ApiPropertyOptional({ enum: SKUGuildType, default: SKUGuildType.GOLD })
|
||||
// @IsEnum(SKUGuildType)
|
||||
// type: SKUGuildType = SKUGuildType.GOLD
|
||||
|
||||
@ApiPropertyOptional({ default: true })
|
||||
@IsBoolean()
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
TspProviderType,
|
||||
} from '@/generated/prisma/enums'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { GoldKarat, SKUGuildType, TspProviderCustomerType } from 'common/enums/enums'
|
||||
import { GoldKarat, TspProviderCustomerType } from 'common/enums/enums'
|
||||
import { ResponseMapper } from 'common/response/response-mapper'
|
||||
|
||||
@Injectable()
|
||||
@@ -80,7 +80,7 @@ export class EnumsService {
|
||||
TspProviderCustomerType,
|
||||
'TspProviderCustomerType',
|
||||
),
|
||||
SKUGuildType: this.prepareData(SKUGuildType, 'SKUGuildType'),
|
||||
// SKUGuildType: this.prepareData(SKUGuildType, 'SKUGuildType'),
|
||||
InvoiceTemplateType: this.prepareData(InvoiceTemplateType, 'InvoiceTemplateType'),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
import { prismaAdapter } from '@/lib/prisma'
|
||||
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'
|
||||
import { PrismaMariaDb } from '@prisma/adapter-mariadb'
|
||||
import 'dotenv/config'
|
||||
import { env } from 'prisma/config'
|
||||
import { PrismaClient } from '../generated/prisma/client'
|
||||
import { getPrismaOptions } from './prisma-config.service'
|
||||
|
||||
@Injectable()
|
||||
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
||||
constructor() {
|
||||
const adapter = new PrismaMariaDb({
|
||||
host: env('DATABASE_HOST'),
|
||||
user: env('DATABASE_USER'),
|
||||
password: env('DATABASE_PASSWORD'),
|
||||
database: env('DATABASE_NAME'),
|
||||
port: env('DATABASE_PORT') ? Number(env('DATABASE_PORT')) : 3306,
|
||||
connectionLimit: 10,
|
||||
})
|
||||
const adapter = prismaAdapter
|
||||
|
||||
const prismaOptions = getPrismaOptions()
|
||||
super({ ...prismaOptions, adapter })
|
||||
|
||||
Reference in New Issue
Block a user