Шаги схемы вынесены в свой каталог, и сверка их снова видит
- шаги PocketBase переехали из файла в пакет internal/adapter/repo/pocketbase/migrations, файл на шаг с именем зарегистрированного шага; туда же имена коллекций, срок сессии — в provider.go - ключ migrations в docs/.docs.json наведён на этот каталог: прежнее значение указывало на несуществующий migrations/, и шаг гейта проходил зелёным при всякой правке схемы - app.go подключает пакет шагов явным пустым импортом: пропавшая ссылка на константы унесла бы регистрацию, и хранилище поднялось бы без коллекций
This commit is contained in:
@@ -10,13 +10,15 @@ import (
|
||||
|
||||
pb "github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
)
|
||||
|
||||
// Имена коллекций. Они же — часть пути к файлу в раскладке хранилища и часть
|
||||
// адреса ссылки на него, поэтому меняются только новым шагом схемы.
|
||||
const (
|
||||
FilesCollection = "files"
|
||||
JobsCollection = "transcribe_jobs"
|
||||
// Шаги схемы регистрируются загрузкой своего пакета, а накатывает их
|
||||
// `RunAllMigrations` ниже. Импорт здесь пустой и явный, хотя соседние файлы
|
||||
// пакета и так берут оттуда имена коллекций: день, когда имена перестанут
|
||||
// читаться отсюда, унёс бы вместе с последней ссылкой и регистрацию — список
|
||||
// шагов остался бы пустым, `RunAllMigrations` вернул бы `nil`, и приложение
|
||||
// поднялось бы здоровым, но без коллекций. Отказ вылез бы не на старте, а на
|
||||
// первом приёме записи.
|
||||
_ "git.vakhrushev.me/av/transcriber/internal/adapter/repo/pocketbase/migrations"
|
||||
)
|
||||
|
||||
// New создаёт приложение хранилища на заданном каталоге данных и приводит его в
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/contract"
|
||||
"git.vakhrushev.me/av/transcriber/internal/entity"
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/adapter/repo/pocketbase/migrations"
|
||||
)
|
||||
|
||||
// workFile — рабочая копия файла на диске. Живёт во временном каталоге
|
||||
@@ -82,7 +84,7 @@ func (repo *FileRepository) Stage(ext string, content io.Reader) (contract.WorkF
|
||||
}
|
||||
|
||||
func (repo *FileRepository) Localize(fileID string) (contract.WorkFile, error) {
|
||||
record, err := repo.app.FindRecordById(FilesCollection, fileID)
|
||||
record, err := repo.app.FindRecordById(migrations.FilesCollection, fileID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find file %s: %w", fileID, err)
|
||||
}
|
||||
@@ -115,7 +117,7 @@ func (repo *FileRepository) Localize(fileID string) (contract.WorkFile, error) {
|
||||
// хранилище не попадает — путь к файлу читается в журнале, и инвариант
|
||||
// приватности этого не допускает. Свой суффикс хранилище допишет само.
|
||||
func (repo *FileRepository) CreateLocal(name string, work contract.WorkFile) (*entity.File, error) {
|
||||
collection, err := findCollection(repo.app, FilesCollection)
|
||||
collection, err := findCollection(repo.app, migrations.FilesCollection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -142,7 +144,7 @@ func (repo *FileRepository) CreateLocal(name string, work contract.WorkFile) (*e
|
||||
}
|
||||
|
||||
func (repo *FileRepository) CreateRemote(objectKey string, size int64) (*entity.File, error) {
|
||||
collection, err := findCollection(repo.app, FilesCollection)
|
||||
collection, err := findCollection(repo.app, migrations.FilesCollection)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -160,7 +162,7 @@ func (repo *FileRepository) CreateRemote(objectKey string, size int64) (*entity.
|
||||
}
|
||||
|
||||
func (repo *FileRepository) GetByID(id string) (*entity.File, error) {
|
||||
record, err := repo.app.FindRecordById(FilesCollection, id)
|
||||
record, err := repo.app.FindRecordById(migrations.FilesCollection, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get file: %w", err)
|
||||
}
|
||||
@@ -168,7 +170,7 @@ func (repo *FileRepository) GetByID(id string) (*entity.File, error) {
|
||||
}
|
||||
|
||||
func (repo *FileRepository) Open(fileID string) (io.ReadCloser, error) {
|
||||
record, err := repo.app.FindRecordById(FilesCollection, fileID)
|
||||
record, err := repo.app.FindRecordById(migrations.FilesCollection, fileID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find file %s: %w", fileID, err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/entity"
|
||||
)
|
||||
|
||||
func up202608110001(app core.App) error {
|
||||
files := core.NewBaseCollection(FilesCollection)
|
||||
files.Fields.Add(
|
||||
// Сам файл. Защищённым поле не помечено намеренно: право прочитать
|
||||
// запись даёт знание её идентификатора, и файл встаёт вровень с опросом
|
||||
// готовности задачи, а не ниже.
|
||||
//
|
||||
// Потолок задан **числом**: нулём библиотека читает не «без предела», а
|
||||
// своё умолчание в 5 МиБ, и на нём отваливалось бы всё длиннее пяти
|
||||
// минут. Число выведено из расчётного потолка записи в шесть часов с
|
||||
// запасом на видео; оно же стоит строкой в docs/database.md.
|
||||
&core.FileField{Name: "file", MaxSelect: 1, MaxSize: entity.MaxRecordSize},
|
||||
// Где лежит копия. Поле названо `location`, а не `storage`: последним
|
||||
// словом зовут само хранилище, и третий смысл развёл бы одно слово по
|
||||
// разным вещам.
|
||||
&core.SelectField{
|
||||
Name: "location",
|
||||
Values: []string{entity.LocationLocal, entity.LocationS3},
|
||||
MaxSelect: 1,
|
||||
Required: true,
|
||||
},
|
||||
// Ключ объекта во внешнем хранилище; у местной копии пуст.
|
||||
&core.TextField{Name: "object_key"},
|
||||
&core.NumberField{Name: "size", OnlyInt: true},
|
||||
&core.AutodateField{Name: "created", OnCreate: true},
|
||||
&core.AutodateField{Name: "updated", OnCreate: true, OnUpdate: true},
|
||||
)
|
||||
|
||||
if err := app.Save(files); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jobs := core.NewBaseCollection(JobsCollection)
|
||||
jobs.Fields.Add(
|
||||
// Перечень состояний закрыт схемой: задача, заведённая в панели руками,
|
||||
// не должна попасть в выборку с состоянием, которого конвейер не знает.
|
||||
&core.SelectField{
|
||||
Name: "state",
|
||||
Values: []string{
|
||||
entity.StateCreated,
|
||||
entity.StateConverted,
|
||||
entity.StateTranscribe,
|
||||
entity.StateDone,
|
||||
entity.StateFailed,
|
||||
entity.StateDead,
|
||||
},
|
||||
MaxSelect: 1,
|
||||
Required: true,
|
||||
},
|
||||
&core.SelectField{
|
||||
Name: "source",
|
||||
Values: []string{entity.SourceUnknown, entity.SourceApi, entity.SourceTelegram},
|
||||
MaxSelect: 1,
|
||||
Required: true,
|
||||
},
|
||||
// Текущий файл задачи: шаг конвейера переставляет ссылку на свой
|
||||
// результат.
|
||||
// Обязательна: задача без записи не может пройти ни одного шага, и
|
||||
// заведённая в панели руками она дошла бы до шага только затем, чтобы
|
||||
// отказать. Компилятор этого не держит — держит схема.
|
||||
&core.RelationField{
|
||||
Name: "file",
|
||||
CollectionId: files.Id,
|
||||
MaxSelect: 1,
|
||||
Required: true,
|
||||
},
|
||||
&core.TextField{Name: "error_text"},
|
||||
&core.TextField{Name: "acquisition_id"},
|
||||
&core.DateField{Name: "acquire_time"},
|
||||
&core.DateField{Name: "delay_time"},
|
||||
// Число попыток: растёт при каждом захвате, обнуляется на шаге,
|
||||
// завершившемся без отказа.
|
||||
&core.NumberField{Name: "attempts", OnlyInt: true, Min: ptr(0.0)},
|
||||
&core.TextField{Name: "recognition_op_id"},
|
||||
&core.EditorField{Name: "transcription_text"},
|
||||
&core.NumberField{Name: "tg_chat_id", OnlyInt: true},
|
||||
&core.NumberField{Name: "tg_reply_message_id", OnlyInt: true},
|
||||
&core.AutodateField{Name: "created", OnCreate: true},
|
||||
&core.AutodateField{Name: "updated", OnCreate: true, OnUpdate: true},
|
||||
)
|
||||
|
||||
// Выборка воркера идёт по состоянию, паузе и сроку захвата — индекс по
|
||||
// состоянию снимает полный перебор, который был у прежней таблицы.
|
||||
jobs.AddIndex("idx_transcribe_jobs_state", false, "state", "")
|
||||
|
||||
return app.Save(jobs)
|
||||
}
|
||||
|
||||
func down202608110001(app core.App) error {
|
||||
// Порядок обратный порядку заведения: задачи ссылаются на файлы.
|
||||
for _, name := range []string{JobsCollection, FilesCollection} {
|
||||
collection, err := app.FindCollectionByNameOrId(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if err := app.Delete(collection); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+1
-129
@@ -1,138 +1,12 @@
|
||||
package pocketbase
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/migrations"
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/entity"
|
||||
)
|
||||
|
||||
// Схема заводится версионированными шагами, и применённый шаг не переписывается
|
||||
// — только новым шагом. Инвариант проекта перенесён дословно: хранилище считает
|
||||
// применённое по имени файла шага.
|
||||
//
|
||||
// Шаг регистрируется в списке приложения при загрузке пакета, а накатывает его
|
||||
// `apis.Serve` прежде, чем поднять сервер.
|
||||
func init() {
|
||||
migrations.Register(up202608110001, down202608110001, "202608110001_init.go")
|
||||
migrations.Register(up202608120001, down202608120001, "202608120001_oidc_login.go")
|
||||
}
|
||||
|
||||
func up202608110001(app core.App) error {
|
||||
files := core.NewBaseCollection(FilesCollection)
|
||||
files.Fields.Add(
|
||||
// Сам файл. Защищённым поле не помечено намеренно: право прочитать
|
||||
// запись даёт знание её идентификатора, и файл встаёт вровень с опросом
|
||||
// готовности задачи, а не ниже.
|
||||
//
|
||||
// Потолок задан **числом**: нулём библиотека читает не «без предела», а
|
||||
// своё умолчание в 5 МиБ, и на нём отваливалось бы всё длиннее пяти
|
||||
// минут. Число выведено из расчётного потолка записи в шесть часов с
|
||||
// запасом на видео; оно же стоит строкой в docs/database.md.
|
||||
&core.FileField{Name: "file", MaxSelect: 1, MaxSize: entity.MaxRecordSize},
|
||||
// Где лежит копия. Поле названо `location`, а не `storage`: последним
|
||||
// словом зовут само хранилище, и третий смысл развёл бы одно слово по
|
||||
// разным вещам.
|
||||
&core.SelectField{
|
||||
Name: "location",
|
||||
Values: []string{entity.LocationLocal, entity.LocationS3},
|
||||
MaxSelect: 1,
|
||||
Required: true,
|
||||
},
|
||||
// Ключ объекта во внешнем хранилище; у местной копии пуст.
|
||||
&core.TextField{Name: "object_key"},
|
||||
&core.NumberField{Name: "size", OnlyInt: true},
|
||||
&core.AutodateField{Name: "created", OnCreate: true},
|
||||
&core.AutodateField{Name: "updated", OnCreate: true, OnUpdate: true},
|
||||
)
|
||||
|
||||
if err := app.Save(files); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jobs := core.NewBaseCollection(JobsCollection)
|
||||
jobs.Fields.Add(
|
||||
// Перечень состояний закрыт схемой: задача, заведённая в панели руками,
|
||||
// не должна попасть в выборку с состоянием, которого конвейер не знает.
|
||||
&core.SelectField{
|
||||
Name: "state",
|
||||
Values: []string{
|
||||
entity.StateCreated,
|
||||
entity.StateConverted,
|
||||
entity.StateTranscribe,
|
||||
entity.StateDone,
|
||||
entity.StateFailed,
|
||||
entity.StateDead,
|
||||
},
|
||||
MaxSelect: 1,
|
||||
Required: true,
|
||||
},
|
||||
&core.SelectField{
|
||||
Name: "source",
|
||||
Values: []string{entity.SourceUnknown, entity.SourceApi, entity.SourceTelegram},
|
||||
MaxSelect: 1,
|
||||
Required: true,
|
||||
},
|
||||
// Текущий файл задачи: шаг конвейера переставляет ссылку на свой
|
||||
// результат.
|
||||
// Обязательна: задача без записи не может пройти ни одного шага, и
|
||||
// заведённая в панели руками она дошла бы до шага только затем, чтобы
|
||||
// отказать. Компилятор этого не держит — держит схема.
|
||||
&core.RelationField{
|
||||
Name: "file",
|
||||
CollectionId: files.Id,
|
||||
MaxSelect: 1,
|
||||
Required: true,
|
||||
},
|
||||
&core.TextField{Name: "error_text"},
|
||||
&core.TextField{Name: "acquisition_id"},
|
||||
&core.DateField{Name: "acquire_time"},
|
||||
&core.DateField{Name: "delay_time"},
|
||||
// Число попыток: растёт при каждом захвате, обнуляется на шаге,
|
||||
// завершившемся без отказа.
|
||||
&core.NumberField{Name: "attempts", OnlyInt: true, Min: ptr(0.0)},
|
||||
&core.TextField{Name: "recognition_op_id"},
|
||||
&core.EditorField{Name: "transcription_text"},
|
||||
&core.NumberField{Name: "tg_chat_id", OnlyInt: true},
|
||||
&core.NumberField{Name: "tg_reply_message_id", OnlyInt: true},
|
||||
&core.AutodateField{Name: "created", OnCreate: true},
|
||||
&core.AutodateField{Name: "updated", OnCreate: true, OnUpdate: true},
|
||||
)
|
||||
|
||||
// Выборка воркера идёт по состоянию, паузе и сроку захвата — индекс по
|
||||
// состоянию снимает полный перебор, который был у прежней таблицы.
|
||||
jobs.AddIndex("idx_transcribe_jobs_state", false, "state", "")
|
||||
|
||||
return app.Save(jobs)
|
||||
}
|
||||
|
||||
func down202608110001(app core.App) error {
|
||||
// Порядок обратный порядку заведения: задачи ссылаются на файлы.
|
||||
for _, name := range []string{JobsCollection, FilesCollection} {
|
||||
collection, err := app.FindCollectionByNameOrId(name)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if err := app.Delete(collection); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SessionDuration — сколько живёт сессия вошедшего, семь суток. Число выбрано
|
||||
// решением владельца от 2026-08-12; умолчание библиотеки в пять суток не
|
||||
// применяется, потому что оно никем не выбрано.
|
||||
//
|
||||
// Применяется оно не шагом схемы, а при каждом подъёме — вместе с настройками
|
||||
// провайдера. Причина та же: применённый шаг не переписывается, и число,
|
||||
// положенное туда, разошлось бы со сроком жизни куки при первой же правке —
|
||||
// браузер получил бы новый срок, а хранилище продолжило выдавать прежний.
|
||||
const SessionDuration = 7 * 24 * 60 * 60
|
||||
|
||||
// defaultAuthTokenDuration — умолчание библиотеки, к которому возвращает откат.
|
||||
const defaultAuthTokenDuration = 1209600
|
||||
|
||||
@@ -248,5 +122,3 @@ func down202608120001(app core.App) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
@@ -0,0 +1,35 @@
|
||||
// Package migrations — шаги схемы хранилища и имена коллекций, которые они
|
||||
// заводят.
|
||||
//
|
||||
// Схема заводится версионированными шагами, и применённый шаг не переписывается
|
||||
// — только новым шагом. Инвариант проекта перенесён дословно: хранилище считает
|
||||
// применённое по **имени шага**, а не по пути файла, поэтому имена в
|
||||
// `Register` ниже не переносятся и не переименовываются, даже если файл переехал.
|
||||
//
|
||||
// Шаги лежат своим каталогом, а не файлом внутри пакета репозитория, и причина
|
||||
// внешняя: сверка документов ловит изменённый шаг схемы при нетронутом
|
||||
// `docs/database.md` по префиксу пути (`docs/.docs.json`, ключ `migrations`), а
|
||||
// префикс наводится только на каталог. Пока шаги лежали файлом, наводить его
|
||||
// было не на что, и проверка молчала на всякой правке схемы.
|
||||
package migrations
|
||||
|
||||
import (
|
||||
pbmigrations "github.com/pocketbase/pocketbase/migrations"
|
||||
)
|
||||
|
||||
// Имена коллекций живут здесь, рядом с шагом, который их заводит. Они же — часть
|
||||
// пути к файлу в раскладке хранилища и часть адреса ссылки на него, поэтому
|
||||
// меняются только новым шагом схемы.
|
||||
const (
|
||||
FilesCollection = "files"
|
||||
JobsCollection = "transcribe_jobs"
|
||||
)
|
||||
|
||||
// Шаг регистрируется в списке приложения при загрузке пакета, а накатывает его
|
||||
// `apis.Serve` прежде, чем поднять сервер.
|
||||
func init() {
|
||||
pbmigrations.Register(up202608110001, down202608110001, "202608110001_init.go")
|
||||
pbmigrations.Register(up202608120001, down202608120001, "202608120001_oidc_login.go")
|
||||
}
|
||||
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
@@ -2,6 +2,8 @@ package pocketbase
|
||||
|
||||
import (
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/adapter/repo/pocketbase/migrations"
|
||||
)
|
||||
|
||||
// BindPanelRules подчиняет правку задачи в панели тем же правилам перехода, что
|
||||
@@ -20,7 +22,7 @@ import (
|
||||
// стиралась бы тем же сохранением, а число попыток мёртвой задачи — которое
|
||||
// переход хранит намеренно — приходило бы владельцу нулём.
|
||||
func BindPanelRules(app core.App) {
|
||||
app.OnRecordUpdateRequest(JobsCollection).BindFunc(func(e *core.RecordRequestEvent) error {
|
||||
app.OnRecordUpdateRequest(migrations.JobsCollection).BindFunc(func(e *core.RecordRequestEvent) error {
|
||||
original := e.Record.Original()
|
||||
if original == nil || original.GetString("state") == e.Record.GetString("state") {
|
||||
return e.Next()
|
||||
|
||||
@@ -10,6 +10,17 @@ import (
|
||||
// как обобщённый OIDC и по нему же ищет настройку при обмене кода.
|
||||
const ProviderName = "oidc"
|
||||
|
||||
// SessionDuration — сколько живёт сессия вошедшего, семь суток. Число выбрано
|
||||
// решением владельца от 2026-08-12; умолчание библиотеки в пять суток не
|
||||
// применяется, потому что оно никем не выбрано.
|
||||
//
|
||||
// Применяется оно не шагом схемы, а при каждом подъёме — вместе с настройками
|
||||
// провайдера, и потому живёт здесь, а не в каталоге шагов. Причина та же:
|
||||
// применённый шаг не переписывается, и число, положенное туда, разошлось бы со
|
||||
// сроком жизни куки при первой же правке — браузер получил бы новый срок, а
|
||||
// хранилище продолжило выдавать прежний.
|
||||
const SessionDuration = 7 * 24 * 60 * 60
|
||||
|
||||
// ProviderSettings — то, что приезжает из конфига и приводится к настройкам
|
||||
// коллекции.
|
||||
type ProviderSettings struct {
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/contract"
|
||||
"git.vakhrushev.me/av/transcriber/internal/entity"
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/adapter/repo/pocketbase/migrations"
|
||||
)
|
||||
|
||||
type TranscriptJobRepository struct {
|
||||
@@ -23,7 +25,7 @@ func NewTranscriptJobRepository(app core.App) *TranscriptJobRepository {
|
||||
}
|
||||
|
||||
func (repo *TranscriptJobRepository) Create(job *entity.TranscribeJob) error {
|
||||
collection, err := findCollection(repo.app, JobsCollection)
|
||||
collection, err := findCollection(repo.app, migrations.JobsCollection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -50,7 +52,7 @@ func (repo *TranscriptJobRepository) Create(job *entity.TranscribeJob) error {
|
||||
// LostAcquisitionError и результата не пишет.
|
||||
func (repo *TranscriptJobRepository) Save(job *entity.TranscribeJob, holder string) error {
|
||||
err := repo.app.RunInTransaction(func(txApp core.App) error {
|
||||
record, err := txApp.FindRecordById(JobsCollection, job.Id)
|
||||
record, err := txApp.FindRecordById(migrations.JobsCollection, job.Id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find transcribe job: %w", err)
|
||||
}
|
||||
@@ -77,7 +79,7 @@ func (repo *TranscriptJobRepository) Save(job *entity.TranscribeJob, holder stri
|
||||
}
|
||||
|
||||
func (repo *TranscriptJobRepository) GetByID(id string) (*entity.TranscribeJob, error) {
|
||||
record, err := repo.app.FindRecordById(JobsCollection, id)
|
||||
record, err := repo.app.FindRecordById(migrations.JobsCollection, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get transcribe job: %w", err)
|
||||
}
|
||||
@@ -108,13 +110,13 @@ func (repo *TranscriptJobRepository) FindAndAcquire(state, acquisitionId string,
|
||||
now := types.NowDateTime()
|
||||
|
||||
query := repo.app.DB().NewQuery(`
|
||||
UPDATE {{` + JobsCollection + `}}
|
||||
UPDATE {{` + migrations.JobsCollection + `}}
|
||||
SET acquisition_id = {:acquisition_id},
|
||||
acquire_time = {:now},
|
||||
attempts = attempts + 1,
|
||||
updated = {:now}
|
||||
WHERE id = (
|
||||
SELECT id FROM {{` + JobsCollection + `}}
|
||||
SELECT id FROM {{` + migrations.JobsCollection + `}}
|
||||
WHERE state = {:state}
|
||||
AND (delay_time = '' OR delay_time IS NULL OR delay_time < {:now})
|
||||
AND (acquisition_id = '' OR acquisition_id IS NULL OR acquire_time < {:rotting})
|
||||
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/contract"
|
||||
"git.vakhrushev.me/av/transcriber/internal/entity"
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/adapter/repo/pocketbase/migrations"
|
||||
)
|
||||
|
||||
// newTestApp поднимает хранилище на пустом каталоге и накатывает схему — тем же
|
||||
@@ -136,7 +138,7 @@ func TestFindAndAcquire_RottenAcquisitionIsHandedOutAgain(t *testing.T) {
|
||||
|
||||
// Задним числом — записью коллекции, то есть тем же слоем, который пишет
|
||||
// собственные времена хранилища.
|
||||
record, err := app.FindRecordById(JobsCollection, job.Id)
|
||||
record, err := app.FindRecordById(migrations.JobsCollection, job.Id)
|
||||
require.NoError(t, err)
|
||||
record.Set("acquire_time", types.NowDateTime().Add(-2*time.Hour))
|
||||
require.NoError(t, app.Save(record))
|
||||
@@ -232,7 +234,7 @@ func TestSave_RefusesWriteFromLostAcquisition(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Задача досталась другому, пока шаг работал.
|
||||
record, err := app.FindRecordById(JobsCollection, mine.Id)
|
||||
record, err := app.FindRecordById(migrations.JobsCollection, mine.Id)
|
||||
require.NoError(t, err)
|
||||
record.Set("acquisition_id", "someone-else")
|
||||
require.NoError(t, app.Save(record))
|
||||
@@ -279,7 +281,7 @@ func TestPanelRules_StateChangeByRequestClearsAcquisition(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acquired.AcquisitionID)
|
||||
|
||||
record, err := app.FindRecordById(JobsCollection, job.Id)
|
||||
record, err := app.FindRecordById(migrations.JobsCollection, job.Id)
|
||||
require.NoError(t, err)
|
||||
record.Set("attempts", 5)
|
||||
record.Set("state", entity.StateDead)
|
||||
@@ -360,7 +362,7 @@ func patchRecord(t *testing.T, app core.App, recordID, body string) {
|
||||
|
||||
req := httptest.NewRequest(
|
||||
http.MethodPatch,
|
||||
"/api/collections/"+JobsCollection+"/records/"+recordID,
|
||||
"/api/collections/"+migrations.JobsCollection+"/records/"+recordID,
|
||||
strings.NewReader(body),
|
||||
)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
Reference in New Issue
Block a user