nameformdb

package
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package nameformdb — общий двигатель пробы «ограничение формы имени ДЕЙСТВУЕТ на живой базе».

Предмет

Ограничение формы имени стоит в схемах, принявших канон #715. «Миграция применилась» и «ограничение отвергает негодную строку» — РАЗНЫЕ утверждения, и до задачи #721 проверялось только первое: перепись пробы, доказывающей второе, давала один сервис из пяти.

Ни число схем, ни имя миграции здесь НЕ выписываются, и это не небрежность. Прежняя редакция называла `715001_resource_name_single_form.sql` и «пять схем»: первое перестало быть верным, когда цепь iam была сведена в одну первичную миграцию (форма стоит в ней), второе — потому что состав пятёрки сменился, а её размер совпал случайно, geo форму снял, iam её принял. Число, пережившее свой предикат, читается как измеренное. Действующий состав печатает переписью гейт `TestNameFormConstraintIsProvenWhereItIsDeclared` на каждом прогоне.

Ограничение базы — последний рубеж канона: код может смениться, вызывающий может пойти мимо слоя домена, но оператор базы отвергнет негодную строку всегда. Ровно поэтому его действие обязано быть ДОКАЗАНО вставкой, а не выведено из того, что файл миграции лежит в дереве.

Почему двигатель общий, а не скопирован в четыре пакета

Копия расходится с оригиналом молча и расходится там, где расхождение не видно, — на составе утверждений. Своего у сервиса ровно одно: как выглядит МИНИМАЛЬНАЯ ЗАКОННАЯ СТРОКА его таблицы. Перечень проверяемых значений, чтение отказа и перепись — одно на всех.

Что проба утверждает

  1. ПЕРЕПИСЬ. Перечень таблиц схемы, несущих форму имени, совпадает с перечнем, который проба обходит. Таблица, получившая форму позже, и таблица, её потерявшая, — обе находка, а не тишина.
  2. ОТРИЦАНИЕ. Имя вне канона отвергается — и отвергается ИМЕННО формой: сверяется не только SQLSTATE 23514, но и имя ограничения, назвавшего отказ. Без второго условия проба зеленела бы на отказе любого соседнего ограничения той же таблицы.
  3. ПОЛОЖИТЕЛЬНЫЙ КОНТРОЛЬ. Каноничное имя вставляется УСПЕШНО. Без него отрицание зеленеет на любой поломке фикстуры: строка, отвергнутая по совершенно другой причине, выглядит как сработавшая защита.

Пункт 3 несёт отдельную ценность, названную самой миграцией: прежние формы требовали БУКВУ первым символом, канон допускает цифру. Поэтому среди принимаемых значений стоит имя, начинающееся с цифры: возврат к прежней форме покраснит пробу, тогда как одно отрицание его бы не заметило.

Почему исход, а не сразу падение

Probe.Check возвращает ОТЧЁТ, а падение производит Probe.Run. Так способность пробы упасть доказуема инъекцией: проба сноса ограничения зовёт Check и утверждает, что находка появилась и назвала координату, — а рядом законный близнец той же формы, на котором находок ноль. Проверка, которая умеет только звать t.Fatal, о себе самой ничего доказать не может.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Execer

type Execer interface {
	Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
	Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
}

Execer — та часть пула, которой пользуется двигатель. Интерфейс, а не *pgxpool.Pool, чтобы пакет не тянул за собой конструкцию пула вызывающего.

type Probe

type Probe struct {
	Schema   string
	Tables   []Table
	Excluded map[string]string
	// OtherForm — таблицы схемы, которые несут форму имени НАМЕРЕННО ДРУГУЮ,
	// чем канон; значение — причина. Отличается от Excluded по существу:
	// исключённая таблица формы не несёт ВОВСЕ, а эта несёт СВОЮ, и та форма
	// действует.
	//
	// Категория заведена схемой iam, где рядом с шестью именуемыми ресурсами
	// живёт идентификатор роли (`roles/vpc.admin`): он не косметическая метка,
	// а то, на что ссылаются привязки, и формой имени не судится — записанное
	// решение владельца (#715). Без третьей категории такую таблицу пришлось бы
	// либо привести к канону (сломав ссылки), либо объявить исключением
	// (соврав: форму она несёт).
	//
	// Перечень проверяется в ОБЕ стороны: запись, чья таблица формы не несёт
	// вовсе, и запись, чья таблица пришла К КАНОНУ, — обе находка. Так
	// послабление истекает само, а не переживает свой предмет.
	OtherForm map[string]string
}

Probe — то, что объявляет вызывающий: схема, таблицы и намеренные исключения.

Excluded — таблицы схемы, которые несут столбец имени и которым форма НЕ ставится ОСОЗНАННО; значение — причина. Перечень проверяется в обе стороны: исключение, которому больше нечего исключать (форму поставили), — находка, а не молчание. Так послабление истекает само, а не переживает свой предмет.

func (Probe) Check

func (p Probe) Check(ctx context.Context, db Execer) (Report, error)

Check исполняет пробу и возвращает отчёт. Ошибку возвращает только тогда, когда прочитать схему не удалось вовсе, — то есть когда отчёт был бы не «находок нет», а «ничего не прочитано».

func (Probe) Run

func (p Probe) Run(ctx context.Context, t *testing.T, db Execer)

Run исполняет пробу и роняет прогон на каждой находке, печатая перепись.

Перепись и уже найденное печатаются ДО вердикта и на ЛЮБОМ исходе — включая отказ чтения схемы. Прежняя редакция роняла прогон сразу и теряла оба: расхождения образцов с каноном находятся ДО обращения к базе, и молчание о них посылало читателя чинить соединение там, где разошёлся перечень значений. Ложного зелёного здесь не было — терялась диагностика, а она и есть то, ради чего пробу читают.

type Report

type Report struct {
	Schema string
	// Probed — таблицы, которые обошла проба.
	Probed []string
	// CarriedInDB — таблицы схемы, реально несущие форму имени.
	CarriedInDB []string
	// BareInDB — таблицы схемы со столбцом имени и БЕЗ формы.
	BareInDB []string
	// Excluded — объявленные намеренные исключения.
	Excluded []string
	// OtherForm — таблицы, объявленные несущими намеренно иную форму.
	OtherForm []string
	// OtherFormWhy — причина по каждой такой таблице.
	OtherFormWhy map[string]string
	// ExcludedWhy — причина по каждому исключению. Поле читается переписью и
	// печатается: причина, которую никто не читает, — то же «принято и
	// проигнорировано», только в оснастке.
	ExcludedWhy map[string]string
	// RejectedPerTable / AcceptedPerTable — сколько значений проверено на таблицу.
	RejectedPerTable int
	AcceptedPerTable int
	// Findings — находки. Пусто = ограничение действует всюду, где объявлено.
	Findings []string
}

Report — исход прогона: объём осмотренного и перечень находок.

Объём печатается ВСЕГДА, в том числе при нуле находок: иначе «находок нет» неотличимо от «ничего не прочитано».

func (Report) Census

func (r Report) Census() string

Census — строка переписи для печати в лог прогона.

type Table

type Table struct {
	Name string
	Row  func(name string, seq int) (sql string, args []any)
}

Table — таблица под пробой и способ собрать для неё МИНИМАЛЬНУЮ ЗАКОННУЮ строку с заданным именем.

Row обязан вернуть INSERT, отвергаемый ТОЛЬКО формой имени: все прочие ограничения таблицы (перечисления состояний, диапазоны, внешние ключи, уникальность, учёт числа ресурсов) он обязан удовлетворять. Иначе положительный контроль перестанет быть контролем — он будет падать по чужой причине.

seq различает строки одного прогона: у большинства таблиц уникальны и ключ, и пара «проект, имя», а у слушателя nlb — ещё и тройка «балансировщик, порт, протокол».

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL