94 lines
2.7 KiB
Markdown
94 lines
2.7 KiB
Markdown
# 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`.
|