fix(projects): находить проекты с кириллицей без учёта регистра
SQLite LOWER() и LIKE понижают только ASCII, поэтому «Сайт и API» не находился и каждый новый VPS с таким проектом создавал дубль; подсказки по «сай» тоже были пустыми. Сравнение перенесено в JS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5e29ff7ec3
commit
d0e262c41d
2 files changed
+27
-23
No files matched your search
@@ -30,6 +30,18 @@ describe('projects routes', () => {
|
|||||||
expect(body[0]?.color).toBe('#ff0000')
|
expect(body[0]?.color).toBe('#ff0000')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('reuses a Cyrillic project regardless of case and suggests it', async () => {
|
||||||
|
projectsRepository.create({ name: 'Сайт и API' })
|
||||||
|
for (const project of ['Сайт и API', 'сайт и api']) {
|
||||||
|
const res = await app.inject({ method: 'POST', url: '/api/vps', payload: { ip: '10.0.0.1', project } })
|
||||||
|
expect(res.statusCode).toBe(201)
|
||||||
|
}
|
||||||
|
const list = (await app.inject({ url: '/api/projects' })).json() as { name: string }[]
|
||||||
|
expect(list.map((p) => p.name)).toEqual(['Сайт и API'])
|
||||||
|
const sug = (await app.inject({ url: `/api/projects/suggest?q=${encodeURIComponent('сай')}` })).json() as { name: string }[]
|
||||||
|
expect(sug.map((p) => p.name)).toEqual(['Сайт и API'])
|
||||||
|
})
|
||||||
|
|
||||||
it('creates project with color and notes', async () => {
|
it('creates project with color and notes', async () => {
|
||||||
const res = await app.inject({
|
const res = await app.inject({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { randomUUID } from 'node:crypto'
|
import { randomUUID } from 'node:crypto'
|
||||||
import { and, eq, like, asc, sql } from 'drizzle-orm'
|
import { and, eq, asc, sql } from 'drizzle-orm'
|
||||||
import { getDb, schema } from '../index.js'
|
import { getDb, schema } from '../index.js'
|
||||||
import { getCurrentSpaceId } from '../space-context.js'
|
import { getCurrentSpaceId } from '../space-context.js'
|
||||||
|
|
||||||
@@ -13,17 +13,18 @@ export function findProjectByNameCaseInsensitive(
|
|||||||
): (typeof schema.serverProjects.$inferSelect) | undefined {
|
): (typeof schema.serverProjects.$inferSelect) | undefined {
|
||||||
const n = normalizeProjectNameInput(name)
|
const n = normalizeProjectNameInput(name)
|
||||||
if (!n) return undefined
|
if (!n) return undefined
|
||||||
const spaceId = getCurrentSpaceId()
|
// SQLite LOWER()/LIKE fold ASCII only — «Сайт» never matched «сайт», so each VPS created a duplicate project.
|
||||||
|
const key = n.toLowerCase()
|
||||||
|
return listSpaceProjects().find((p) => p.name.trim().toLowerCase() === key)
|
||||||
|
}
|
||||||
|
|
||||||
|
function listSpaceProjects() {
|
||||||
return getDb()
|
return getDb()
|
||||||
.select()
|
.select()
|
||||||
.from(schema.serverProjects)
|
.from(schema.serverProjects)
|
||||||
.where(
|
.where(eq(schema.serverProjects.spaceId, getCurrentSpaceId()))
|
||||||
and(
|
.orderBy(asc(schema.serverProjects.name))
|
||||||
eq(schema.serverProjects.spaceId, spaceId),
|
.all()
|
||||||
eq(sql`LOWER(${schema.serverProjects.name})`, n.toLowerCase()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveOrCreateProject(
|
export function resolveOrCreateProject(
|
||||||
@@ -67,20 +68,11 @@ export function projectSuggestions(
|
|||||||
.limit(lim)
|
.limit(lim)
|
||||||
.all()
|
.all()
|
||||||
}
|
}
|
||||||
const esc = term.replace(/\\/g, '\\\\').replace(/%/g, '\\%').replace(/_/g, '\\_')
|
const needle = term.toLowerCase()
|
||||||
const pattern = `%${esc.toLowerCase()}%`
|
return listSpaceProjects()
|
||||||
return db
|
.filter((p) => p.name.toLowerCase().includes(needle))
|
||||||
.select({ id: schema.serverProjects.id, name: schema.serverProjects.name })
|
.slice(0, lim)
|
||||||
.from(schema.serverProjects)
|
.map(({ id, name }) => ({ id, name }))
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(schema.serverProjects.spaceId, spaceId),
|
|
||||||
like(sql`LOWER(${schema.serverProjects.name})`, pattern),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.orderBy(asc(schema.serverProjects.name))
|
|
||||||
.limit(lim)
|
|
||||||
.all()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProjectNameById(id: string): string {
|
export function getProjectNameById(id: string): string {
|
||||||
|
|||||||
Reference in new issue
Block a user