Persistence: move some DB to API struct conversion to API implementation

This commit is contained in:
Sybren A. Stüvel 2022-02-01 16:22:10 +01:00
parent 862ed96af7
commit e598397ba4
4 changed files with 43 additions and 34 deletions

View File

@ -36,9 +36,8 @@ type Flamenco struct {
} }
type PersistenceService interface { type PersistenceService interface {
// StoreJob stores a job in the persistence layer. StoreAuthoredJob(ctx context.Context, authoredJob job_compilers.AuthoredJob) error
StoreJob(ctx context.Context, authoredJob job_compilers.AuthoredJob) error FetchJob(ctx context.Context, jobID string) (*persistence.Job, error)
FetchJob(ctx context.Context, jobID string) (*api.Job, error)
CreateWorker(ctx context.Context, w *persistence.Worker) error CreateWorker(ctx context.Context, w *persistence.Worker) error
FetchWorker(ctx context.Context, uuid string) (*persistence.Worker, error) FetchWorker(ctx context.Context, uuid string) (*persistence.Worker, error)

View File

@ -69,7 +69,7 @@ func (f *Flamenco) SubmitJob(e echo.Context) error {
logger = logger.With().Str("job_id", authoredJob.JobID).Logger() logger = logger.With().Str("job_id", authoredJob.JobID).Logger()
if err := f.persist.StoreJob(ctx, *authoredJob); err != nil { if err := f.persist.StoreAuthoredJob(ctx, *authoredJob); err != nil {
logger.Error().Err(err).Msg("error persisting job in database") logger.Error().Err(err).Msg("error persisting job in database")
return sendAPIError(e, http.StatusInternalServerError, "error persisting job in database") return sendAPIError(e, http.StatusInternalServerError, "error persisting job in database")
} }
@ -92,11 +92,27 @@ func (f *Flamenco) FetchJob(e echo.Context, jobId string) error {
logger.Debug().Msg("fetching job") logger.Debug().Msg("fetching job")
ctx := e.Request().Context() ctx := e.Request().Context()
job, err := f.persist.FetchJob(ctx, jobId) dbJob, err := f.persist.FetchJob(ctx, jobId)
if err != nil { if err != nil {
logger.Warn().Err(err).Msg("cannot fetch job") logger.Warn().Err(err).Msg("cannot fetch job")
return sendAPIError(e, http.StatusNotFound, fmt.Sprintf("job %+v not found", jobId)) return sendAPIError(e, http.StatusNotFound, fmt.Sprintf("job %+v not found", jobId))
} }
return e.JSON(http.StatusOK, job) apiJob := api.Job{
SubmittedJob: api.SubmittedJob{
Name: dbJob.Name,
Priority: dbJob.Priority,
Type: dbJob.JobType,
},
Id: dbJob.UUID,
Created: dbJob.CreatedAt,
Updated: dbJob.UpdatedAt,
Status: api.JobStatus(dbJob.Status),
}
apiJob.Settings = &api.JobSettings{AdditionalProperties: dbJob.Settings}
apiJob.Metadata = &api.JobMetadata{AdditionalProperties: dbJob.Metadata}
return e.JSON(http.StatusOK, apiJob)
} }

View File

@ -38,7 +38,7 @@ type Job struct {
Name string `gorm:"type:varchar(64);not null"` Name string `gorm:"type:varchar(64);not null"`
JobType string `gorm:"type:varchar(32);not null"` JobType string `gorm:"type:varchar(32);not null"`
Priority int8 `gorm:"type:smallint;not null"` Priority int `gorm:"type:smallint;not null"`
Status string `gorm:"type:varchar(32);not null"` // See JobStatusXxxx consts in openapi_types.gen.go Status string `gorm:"type:varchar(32);not null"` // See JobStatusXxxx consts in openapi_types.gen.go
Settings StringInterfaceMap `gorm:"type:jsonb"` Settings StringInterfaceMap `gorm:"type:jsonb"`
@ -106,14 +106,17 @@ func (js *StringStringMap) Scan(value interface{}) error {
return json.Unmarshal(b, &js) return json.Unmarshal(b, &js)
} }
func (db *DB) StoreJob(ctx context.Context, authoredJob job_compilers.AuthoredJob) error { // StoreJob stores an AuthoredJob and its tasks, and saves it to the database.
// The job will be in 'under construction' status. It is up to the caller to transition it to its desired initial status.
func (db *DB) StoreAuthoredJob(ctx context.Context, authoredJob job_compilers.AuthoredJob) error {
return db.gormDB.Transaction(func(tx *gorm.DB) error { return db.gormDB.Transaction(func(tx *gorm.DB) error {
// TODO: separate conversion of struct types from storing things in the database. // TODO: separate conversion of struct types from storing things in the database.
dbJob := Job{ dbJob := Job{
UUID: authoredJob.JobID, UUID: authoredJob.JobID,
Name: authoredJob.Name, Name: authoredJob.Name,
JobType: authoredJob.JobType, JobType: authoredJob.JobType,
Priority: int8(authoredJob.Priority), Status: string(api.JobStatusUnderConstruction),
Priority: authoredJob.Priority,
Settings: StringInterfaceMap(authoredJob.Settings), Settings: StringInterfaceMap(authoredJob.Settings),
Metadata: StringStringMap(authoredJob.Metadata), Metadata: StringStringMap(authoredJob.Metadata),
} }
@ -149,28 +152,12 @@ func (db *DB) StoreJob(ctx context.Context, authoredJob job_compilers.AuthoredJo
}) })
} }
func (db *DB) FetchJob(ctx context.Context, jobID string) (*api.Job, error) { func (db *DB) FetchJob(ctx context.Context, jobUUID string) (*Job, error) {
dbJob := Job{} dbJob := Job{}
findResult := db.gormDB.First(&dbJob, "uuid = ?", jobID) findResult := db.gormDB.First(&dbJob, "uuid = ?", jobUUID)
if findResult.Error != nil { if findResult.Error != nil {
return nil, findResult.Error return nil, findResult.Error
} }
apiJob := api.Job{ return &dbJob, nil
SubmittedJob: api.SubmittedJob{
Name: dbJob.Name,
Priority: int(dbJob.Priority),
Type: dbJob.JobType,
},
Id: dbJob.UUID,
Created: dbJob.CreatedAt,
Updated: dbJob.UpdatedAt,
Status: api.JobStatus(dbJob.Status),
}
apiJob.Settings = &api.JobSettings{AdditionalProperties: dbJob.Settings}
apiJob.Metadata = &api.JobMetadata{AdditionalProperties: dbJob.Metadata}
return &apiJob, nil
} }

View File

@ -27,6 +27,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gitlab.com/blender/flamenco-ng-poc/internal/manager/job_compilers" "gitlab.com/blender/flamenco-ng-poc/internal/manager/job_compilers"
"gitlab.com/blender/flamenco-ng-poc/pkg/api"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -88,7 +89,7 @@ func TestStoreAuthoredJob(t *testing.T) {
Tasks: []job_compilers.AuthoredTask{task1, task2, task3}, Tasks: []job_compilers.AuthoredTask{task1, task2, task3},
} }
err := db.StoreJob(ctx, job) err := db.StoreAuthoredJob(ctx, job)
assert.NoError(t, err) assert.NoError(t, err)
fetchedJob, err := db.FetchJob(ctx, job.JobID) fetchedJob, err := db.FetchJob(ctx, job.JobID)
@ -96,12 +97,13 @@ func TestStoreAuthoredJob(t *testing.T) {
assert.NotNil(t, fetchedJob) assert.NotNil(t, fetchedJob)
// Test contents of fetched job // Test contents of fetched job
assert.Equal(t, job.JobID, fetchedJob.Id) assert.Equal(t, job.JobID, fetchedJob.UUID)
assert.Equal(t, job.Name, fetchedJob.Name) assert.Equal(t, job.Name, fetchedJob.Name)
assert.Equal(t, job.JobType, fetchedJob.Type) assert.Equal(t, job.JobType, fetchedJob.JobType)
assert.Equal(t, job.Priority, fetchedJob.Priority) assert.Equal(t, job.Priority, fetchedJob.Priority)
assert.EqualValues(t, map[string]interface{}(job.Settings), fetchedJob.Settings.AdditionalProperties) assert.Equal(t, string(api.JobStatusUnderConstruction), fetchedJob.Status)
assert.EqualValues(t, map[string]string(job.Metadata), fetchedJob.Metadata.AdditionalProperties) assert.EqualValues(t, map[string]interface{}(job.Settings), fetchedJob.Settings)
assert.EqualValues(t, map[string]string(job.Metadata), fetchedJob.Metadata)
// Fetch tasks of job. // Fetch tasks of job.
var dbJob Job var dbJob Job
@ -111,7 +113,12 @@ func TestStoreAuthoredJob(t *testing.T) {
tx = db.gormDB.Where("job_id = ?", dbJob.ID).Find(&tasks) tx = db.gormDB.Where("job_id = ?", dbJob.ID).Find(&tasks)
assert.NoError(t, tx.Error) assert.NoError(t, tx.Error)
assert.Len(t, tasks, 3) if len(tasks) != 3 {
t.Fatalf("expected 3 tasks, got %d", len(tasks))
}
// TODO: test task contents. // TODO: test task contents.
assert.Equal(t, string(api.TaskStatusQueued), tasks[0].Status)
assert.Equal(t, string(api.TaskStatusQueued), tasks[1].Status)
assert.Equal(t, string(api.TaskStatusQueued), tasks[2].Status)
} }