Files
bible/rules/patterns/identifier-normalization/contract.md
2026-03-01 22:07:19 +03:00

94 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Contract: Identifier Normalization
Version: 1.0
## Purpose
Правила хранения и сравнения идентификаторов оборудования:
серийные номера, вендоры, версии прошивок, партномера, артикулы.
---
## Правило
Оригинальное значение **сохраняется как пришло** — регистр не меняется.
Все сравнения, поиск и дедупликация выполняются **без учёта регистра**.
```
Пришло: "SN-001-ABC" → хранится: "SN-001-ABC"
Пришло: "sn-001-abc" → это тот же объект, не дубликат
Пришло: "Sn-001-Abc" → то же самое
```
---
## Применяется к полям
- Серийный номер (`serial_number`, `serial`)
- Вендор / производитель (`vendor`, `manufacturer`)
- Версия прошивки (`firmware_version`, `fw_version`)
- Партномер (`part_number`, `part_no`)
- Артикул (`article`, `sku`)
---
## Реализация
### Go — сравнение
```go
import "strings"
func SameIdentifier(a, b string) bool {
return strings.EqualFold(a, b)
}
```
### Go — дедупликация
```go
func deduplicateBySerial(items []Device) []Device {
seen := make(map[string]struct{})
result := items[:0]
for _, item := range items {
key := strings.ToLower(item.SerialNumber)
if _, exists := seen[key]; !exists {
seen[key] = struct{}{}
result = append(result, item)
}
}
return result
}
```
Ключ в map — всегда `strings.ToLower(value)`. Сам объект сохраняется с оригинальным значением.
### SQL — поиск и уникальность
Поиск:
```sql
SELECT * FROM devices WHERE LOWER(serial_number) = LOWER(?);
```
Уникальный индекс (MySQL / MariaDB):
```sql
-- Collation ci обеспечивает case-insensitive уникальность
ALTER TABLE devices MODIFY serial_number VARCHAR(255)
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE devices ADD UNIQUE INDEX uniq_serial (serial_number);
```
SQLite:
```sql
CREATE UNIQUE INDEX uniq_serial ON devices (LOWER(serial_number));
```
---
## Что не делать
- Не приводить значение к нижнему или верхнему регистру перед сохранением.
- Не считать `"SN-001"` и `"sn-001"` разными объектами.
- Не использовать `==` для сравнения идентификаторов в Go — только `strings.EqualFold`.