Skip to content

Commit 8892a46

Browse files
authored
Added CreatedAt and UpdatedAt (#111)
* Added CreatedAt and UpdatedAt * Added TimeMetadata to response models * Changed UpdatedAt & CreatedAt to be nullable * Updated CHANGELOG.md * Fixed linting
1 parent bc4d776 commit 8892a46

File tree

12 files changed

+89
-18
lines changed

12 files changed

+89
-18
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ This project tries to follow [SemVer 2.0.0](https://semver.org/).
8383

8484
- Added dependency on `gorm.io/driver/sqlite`. (#86)
8585

86+
- Added `updatedAt` and `createdAt` fields to the following models: (#111)
87+
88+
- `response.Artifact`
89+
- `response.Branch`
90+
- `response.Build`
91+
- `response.Project`
92+
- `response.Provider`
93+
- `response.TestResultDetail`
94+
- `response.TestResultSummary`
95+
- `response.Token`
96+
97+
Objects created and updated before this patch will have the value `null`, but
98+
will get a valid date on first update, such as on first refresh for a project.
99+
86100
- Fixed bug where unable to delete a Project without first deleting all child
87101
objects. (#64)
88102

pkg/model/database/database.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ import (
2727
// One seems to take precedence, but to make sure and to keep the code
2828
// consistent we add it to both referencing fields.
2929

30+
// TimeMetadata contains fields that GORM will recognize and update
31+
// automatically for us.
32+
//
33+
// Docs: https://gorm.io/docs/models.html#Creating-Updating-Time-Unix-Milli-Nano-Seconds-Tracking
34+
type TimeMetadata struct {
35+
CreatedAt *time.Time `gorm:"nullable"`
36+
UpdatedAt *time.Time `gorm:"nullable"`
37+
}
38+
3039
// SafeSQLName represents a value that is safe to use as an SQL table or column
3140
// name without the need of escaping.
3241
//
@@ -68,6 +77,7 @@ var ProviderColumns = struct {
6877
// importance are the URL field of where to find the remote, and the token field
6978
// used to authenticate.
7079
type Provider struct {
80+
TimeMetadata
7181
ProviderID uint `gorm:"primaryKey"`
7282
Name string `gorm:"size:20;not null"`
7383
URL string `gorm:"size:500;not null"`
@@ -103,6 +113,7 @@ var TokenColumns = struct {
103113

104114
// Token holds credentials for a remote provider.
105115
type Token struct {
116+
TimeMetadata
106117
TokenID uint `gorm:"primaryKey"`
107118
Token string `gorm:"size:500;not null"`
108119
UserName string `gorm:"size:500;not null;default:''"`
@@ -165,6 +176,7 @@ var ProjectColumns = struct {
165176
// to be populated with data from the remote provider, such as the description
166177
// and avatar.
167178
type Project struct {
179+
TimeMetadata
168180
ProjectID uint `gorm:"primaryKey"`
169181
RemoteProjectID string `gorm:"not null;default:''"`
170182
Name string `gorm:"size:500;not null"`
@@ -209,6 +221,7 @@ var BranchColumns = struct {
209221
// Branch is a single branch in the VCS that can be targeted during builds.
210222
// For example a Git branch.
211223
type Branch struct {
224+
TimeMetadata
212225
BranchID uint `gorm:"primaryKey"`
213226
ProjectID uint `gorm:"not null;index:branch_idx_project_id"`
214227
Project *Project `gorm:"foreignKey:ProjectID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
@@ -269,6 +282,7 @@ var BuildColumns = struct {
269282
// Build holds data about the state of a build. Which parameters was used to
270283
// start it, what status it holds, et.al.
271284
type Build struct {
285+
TimeMetadata
272286
BuildID uint `gorm:"primaryKey"`
273287
StatusID BuildStatus `gorm:"not null"`
274288
ProjectID uint `gorm:"not null;index:build_idx_project_id"`
@@ -385,6 +399,7 @@ var ArtifactFields = struct {
385399
// Artifact holds the binary data as well as metadata about that binary such as
386400
// the file name and which build it belongs to.
387401
type Artifact struct {
402+
TimeMetadata
388403
ArtifactID uint `gorm:"primaryKey"`
389404
BuildID uint `gorm:"not null;index:artifact_idx_build_id"`
390405
Build *Build `gorm:"foreignKey:BuildID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
@@ -404,6 +419,7 @@ var TestResultSummaryFields = struct {
404419

405420
// TestResultSummary contains data about a single test result file.
406421
type TestResultSummary struct {
422+
TimeMetadata
407423
TestResultSummaryID uint `gorm:"primaryKey"`
408424
FileName string `gorm:"not null;default:''"`
409425
ArtifactID uint `gorm:"not null;index:testresultsummary_idx_artifact_id"`
@@ -430,6 +446,7 @@ const (
430446

431447
// TestResultDetail contains data about a single test in a test result file.
432448
type TestResultDetail struct {
449+
TimeMetadata
433450
TestResultDetailID uint `gorm:"primaryKey"`
434451
ArtifactID uint `gorm:"not null;index:testresultdetail_idx_artifact_id"`
435452
Artifact *Artifact `gorm:"foreignKey:ArtifactID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL"`

pkg/model/response/response.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ import (
88
"gopkg.in/guregu/null.v4"
99
)
1010

11+
// TimeMetadata contains fields of when an object was created/added to the
12+
// database, and when any field was last updated.
13+
type TimeMetadata struct {
14+
UpdatedAt *time.Time `json:"updatedAt" format:"date-time" extensions:"x-nullable"`
15+
CreatedAt *time.Time `json:"createdAt" format:"date-time" extensions:"x-nullable"`
16+
}
17+
1118
// ArtifactJSONFields holds the JSON field names for each field.
1219
// Useful in ordering statements to map the correct field to the correct
1320
// database column.
@@ -24,6 +31,7 @@ var ArtifactJSONFields = struct {
2431
// Artifact holds the binary data as well as metadata about that binary such as
2532
// the file name and which build it belongs to.
2633
type Artifact struct {
34+
TimeMetadata
2735
ArtifactID uint `json:"artifactId" minimum:"0"`
2836
BuildID uint `json:"buildId" minimum:"0"`
2937
Name string `json:"name"`
@@ -32,12 +40,14 @@ type Artifact struct {
3240

3341
// ArtifactMetadata contains the file name and artifact ID of an Artifact.
3442
type ArtifactMetadata struct {
43+
TimeMetadata
3544
FileName string `json:"fileName"`
3645
ArtifactID uint `json:"artifactId" minimum:"0"`
3746
}
3847

3948
// Branch holds details about a project's branch.
4049
type Branch struct {
50+
TimeMetadata
4151
BranchID uint `json:"branchId" minimum:"0"`
4252
ProjectID uint `json:"projectId" minimum:"0"`
4353
Name string `json:"name"`
@@ -78,6 +88,7 @@ var BuildJSONFields = struct {
7888
// Build holds data about the state of a build. Which parameters was used to
7989
// start it, what status it holds, et.al.
8090
type Build struct {
91+
TimeMetadata
8192
BuildID uint `json:"buildId" minimum:"0"`
8293
StatusID int `json:"statusId" enums:"0,1,2,3"`
8394
Status BuildStatus `json:"status" enums:"Scheduling,Running,Completed,Failed"`
@@ -214,6 +225,7 @@ var ProjectJSONFields = struct {
214225

215226
// Project holds details about a project.
216227
type Project struct {
228+
TimeMetadata
217229
ProjectID uint `json:"projectId" minimum:"0"`
218230
RemoteProjectID string `json:"remoteProjectId"`
219231
Name string `json:"name"`
@@ -248,6 +260,7 @@ var ProviderJSONFields = struct {
248260
// importance are the URL field of where to find the remote, and the token field
249261
// used to authenticate.
250262
type Provider struct {
263+
TimeMetadata
251264
ProviderID uint `json:"providerId" minimum:"0"`
252265
Name ProviderName `json:"name" enums:"azuredevops,gitlab,github"`
253266
URL string `json:"url"`
@@ -291,6 +304,7 @@ const (
291304

292305
// TestResultDetail contains data about a single test in a test result file.
293306
type TestResultDetail struct {
307+
TimeMetadata
294308
TestResultDetailID uint `json:"testResultDetailId" minimum:"0"`
295309
ArtifactID uint `json:"artifactId" minimum:"0"`
296310
BuildID uint `json:"buildId" minimum:"0"`
@@ -324,6 +338,7 @@ const (
324338

325339
// TestResultSummary contains data about a single test result file.
326340
type TestResultSummary struct {
341+
TimeMetadata
327342
TestResultSummaryID uint `json:"testResultSummaryId" minimum:"0"`
328343
FileName string `json:"fileName"`
329344
ArtifactID uint `json:"artifactId" minimum:"0"`
@@ -359,6 +374,7 @@ var TokenJSONFields = struct {
359374

360375
// Token holds credentials for a remote provider.
361376
type Token struct {
377+
TimeMetadata
362378
TokenID uint `json:"tokenId" minimum:"0"`
363379
Token string `json:"token" format:"password"`
364380
UserName string `json:"userName"`

pkg/modelconv/artifactconv.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import (
88
// DBArtifactToResponse converts a database artifact to a response artifact.
99
func DBArtifactToResponse(dbArtifact database.Artifact) response.Artifact {
1010
return response.Artifact{
11-
ArtifactID: dbArtifact.ArtifactID,
12-
BuildID: dbArtifact.BuildID,
13-
Name: dbArtifact.Name,
14-
FileName: dbArtifact.FileName,
11+
TimeMetadata: DBTimeMetadataToResponse(dbArtifact.TimeMetadata),
12+
ArtifactID: dbArtifact.ArtifactID,
13+
BuildID: dbArtifact.BuildID,
14+
Name: dbArtifact.Name,
15+
FileName: dbArtifact.FileName,
1516
}
1617
}
1718

pkg/modelconv/branchconv.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ func DBBranchesToResponses(dbBranches []database.Branch) []response.Branch {
3333
// DBBranchToResponse converts a database branch to a response branch.
3434
func DBBranchToResponse(dbBranch database.Branch) response.Branch {
3535
return response.Branch{
36-
BranchID: dbBranch.BranchID,
37-
ProjectID: dbBranch.ProjectID,
38-
Name: dbBranch.Name,
39-
Default: dbBranch.Default,
40-
TokenID: dbBranch.TokenID,
36+
TimeMetadata: DBTimeMetadataToResponse(dbBranch.TimeMetadata),
37+
BranchID: dbBranch.BranchID,
38+
ProjectID: dbBranch.ProjectID,
39+
Name: dbBranch.Name,
40+
Default: dbBranch.Default,
41+
TokenID: dbBranch.TokenID,
4142
}
4243
}
4344

pkg/modelconv/buildconv.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ func DBBuildToResponse(dbBuild database.Build) response.Build {
5858
Failed: failed,
5959
}
6060
return response.Build{
61+
TimeMetadata: DBTimeMetadataToResponse(dbBuild.TimeMetadata),
6162
BuildID: dbBuild.BuildID,
6263
StatusID: int(dbBuild.StatusID),
6364
Status: DBBuildStatusToResponse(dbBuild.StatusID),

pkg/modelconv/metadataconv.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package modelconv
2+
3+
import (
4+
"github.com/iver-wharf/wharf-api/pkg/model/database"
5+
"github.com/iver-wharf/wharf-api/pkg/model/response"
6+
)
7+
8+
// DBTimeMetadataToResponse converts a database timestamp metadata to a response
9+
// timestamp metadata.
10+
func DBTimeMetadataToResponse(timeMetadata database.TimeMetadata) response.TimeMetadata {
11+
return response.TimeMetadata{
12+
CreatedAt: timeMetadata.CreatedAt,
13+
UpdatedAt: timeMetadata.UpdatedAt,
14+
}
15+
}

pkg/modelconv/projectconv.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func DBProjectToResponse(dbProject database.Project) response.Project {
3333
Message("Failed to parse build-definition.")
3434
}
3535
return response.Project{
36+
TimeMetadata: DBTimeMetadataToResponse(dbProject.TimeMetadata),
3637
ProjectID: dbProject.ProjectID,
3738
Name: dbProject.Name,
3839
GroupName: dbProject.GroupName,

pkg/modelconv/providerconv.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ func DBProvidersToResponses(dbProviders []database.Provider) []response.Provider
1818
// DBProviderToResponse converts a database provider to a response provider.
1919
func DBProviderToResponse(dbProvider database.Provider) response.Provider {
2020
return response.Provider{
21-
ProviderID: dbProvider.ProviderID,
22-
Name: response.ProviderName(dbProvider.Name),
23-
URL: dbProvider.URL,
24-
TokenID: dbProvider.TokenID,
21+
TimeMetadata: DBTimeMetadataToResponse(dbProvider.TimeMetadata),
22+
ProviderID: dbProvider.ProviderID,
23+
Name: response.ProviderName(dbProvider.Name),
24+
URL: dbProvider.URL,
25+
TokenID: dbProvider.TokenID,
2526
}
2627
}

pkg/modelconv/testresultconv.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func DBTestResultSummariesToResponses(dbSummaries []database.TestResultSummary)
1919
// response test result summary.
2020
func DBTestResultSummaryToResponse(dbSummary database.TestResultSummary) response.TestResultSummary {
2121
return response.TestResultSummary{
22+
TimeMetadata: DBTimeMetadataToResponse(dbSummary.TimeMetadata),
2223
TestResultSummaryID: dbSummary.TestResultSummaryID,
2324
FileName: dbSummary.FileName,
2425
ArtifactID: dbSummary.ArtifactID,
@@ -44,6 +45,7 @@ func DBTestResultDetailsToResponses(dbDetails []database.TestResultDetail) []res
4445
// response test result detail.
4546
func DBTestResultDetailToResponse(dbDetail database.TestResultDetail) response.TestResultDetail {
4647
return response.TestResultDetail{
48+
TimeMetadata: DBTimeMetadataToResponse(dbDetail.TimeMetadata),
4749
TestResultDetailID: dbDetail.TestResultDetailID,
4850
ArtifactID: dbDetail.ArtifactID,
4951
BuildID: dbDetail.BuildID,

0 commit comments

Comments
 (0)