2.7 KiB
2.7 KiB
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 — сравнение
import "strings"
func SameIdentifier(a, b string) bool {
return strings.EqualFold(a, b)
}
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 — поиск и уникальность
Поиск:
SELECT * FROM devices WHERE LOWER(serial_number) = LOWER(?);
Уникальный индекс (MySQL / MariaDB):
-- 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:
CREATE UNIQUE INDEX uniq_serial ON devices (LOWER(serial_number));
Что не делать
- Не приводить значение к нижнему или верхнему регистру перед сохранением.
- Не считать
"SN-001"и"sn-001"разными объектами. - Не использовать
==для сравнения идентификаторов в Go — толькоstrings.EqualFold.