From 026d723d6ccf4fc39c5971633a2e0087cd42a9d7 Mon Sep 17 00:00:00 2001 From: noah Date: Mon, 4 Oct 2021 22:39:37 +0900 Subject: [PATCH 1/5] Add the synced_at field to Perm --- ent/migrate/schema.go | 11 +++--- ent/mutation.go | 56 ++++++++++++++++++++++++++++- ent/perm.go | 12 ++++++- ent/perm/perm.go | 3 ++ ent/perm/where.go | 83 +++++++++++++++++++++++++++++++++++++++++++ ent/perm_create.go | 17 +++++++++ ent/perm_update.go | 26 ++++++++++++++ ent/runtime.go | 4 +-- ent/schema/perm.go | 3 +- 9 files changed, 205 insertions(+), 10 deletions(-) diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 58249a82..8dd24279 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -275,6 +275,7 @@ var ( PermsColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, {Name: "repo_perm", Type: field.TypeEnum, Enums: []string{"read", "write", "admin"}, Default: "read"}, + {Name: "synced_at", Type: field.TypeTime}, {Name: "created_at", Type: field.TypeTime}, {Name: "updated_at", Type: field.TypeTime}, {Name: "repo_id", Type: field.TypeInt64, Nullable: true}, @@ -288,13 +289,13 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "perms_repos_perms", - Columns: []*schema.Column{PermsColumns[4]}, + Columns: []*schema.Column{PermsColumns[5]}, RefColumns: []*schema.Column{ReposColumns[0]}, OnDelete: schema.Cascade, }, { Symbol: "perms_users_perms", - Columns: []*schema.Column{PermsColumns[5]}, + Columns: []*schema.Column{PermsColumns[6]}, RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.Cascade, }, @@ -303,12 +304,12 @@ var ( { Name: "perm_repo_id_user_id", Unique: false, - Columns: []*schema.Column{PermsColumns[4], PermsColumns[5]}, + Columns: []*schema.Column{PermsColumns[5], PermsColumns[6]}, }, { - Name: "perm_user_id_updated_at", + Name: "perm_user_id_synced_at", Unique: false, - Columns: []*schema.Column{PermsColumns[5], PermsColumns[3]}, + Columns: []*schema.Column{PermsColumns[6], PermsColumns[2]}, }, }, } diff --git a/ent/mutation.go b/ent/mutation.go index b6f57598..46041ec8 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -5939,6 +5939,7 @@ type PermMutation struct { typ string id *int repo_perm *perm.RepoPerm + synced_at *time.Time created_at *time.Time updated_at *time.Time clearedFields map[string]struct{} @@ -6066,6 +6067,42 @@ func (m *PermMutation) ResetRepoPerm() { m.repo_perm = nil } +// SetSyncedAt sets the "synced_at" field. +func (m *PermMutation) SetSyncedAt(t time.Time) { + m.synced_at = &t +} + +// SyncedAt returns the value of the "synced_at" field in the mutation. +func (m *PermMutation) SyncedAt() (r time.Time, exists bool) { + v := m.synced_at + if v == nil { + return + } + return *v, true +} + +// OldSyncedAt returns the old "synced_at" field's value of the Perm entity. +// If the Perm object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *PermMutation) OldSyncedAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldSyncedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldSyncedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSyncedAt: %w", err) + } + return oldValue.SyncedAt, nil +} + +// ResetSyncedAt resets all changes to the "synced_at" field. +func (m *PermMutation) ResetSyncedAt() { + m.synced_at = nil +} + // SetCreatedAt sets the "created_at" field. func (m *PermMutation) SetCreatedAt(t time.Time) { m.created_at = &t @@ -6281,10 +6318,13 @@ func (m *PermMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *PermMutation) Fields() []string { - fields := make([]string, 0, 5) + fields := make([]string, 0, 6) if m.repo_perm != nil { fields = append(fields, perm.FieldRepoPerm) } + if m.synced_at != nil { + fields = append(fields, perm.FieldSyncedAt) + } if m.created_at != nil { fields = append(fields, perm.FieldCreatedAt) } @@ -6307,6 +6347,8 @@ func (m *PermMutation) Field(name string) (ent.Value, bool) { switch name { case perm.FieldRepoPerm: return m.RepoPerm() + case perm.FieldSyncedAt: + return m.SyncedAt() case perm.FieldCreatedAt: return m.CreatedAt() case perm.FieldUpdatedAt: @@ -6326,6 +6368,8 @@ func (m *PermMutation) OldField(ctx context.Context, name string) (ent.Value, er switch name { case perm.FieldRepoPerm: return m.OldRepoPerm(ctx) + case perm.FieldSyncedAt: + return m.OldSyncedAt(ctx) case perm.FieldCreatedAt: return m.OldCreatedAt(ctx) case perm.FieldUpdatedAt: @@ -6350,6 +6394,13 @@ func (m *PermMutation) SetField(name string, value ent.Value) error { } m.SetRepoPerm(v) return nil + case perm.FieldSyncedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSyncedAt(v) + return nil case perm.FieldCreatedAt: v, ok := value.(time.Time) if !ok { @@ -6433,6 +6484,9 @@ func (m *PermMutation) ResetField(name string) error { case perm.FieldRepoPerm: m.ResetRepoPerm() return nil + case perm.FieldSyncedAt: + m.ResetSyncedAt() + return nil case perm.FieldCreatedAt: m.ResetCreatedAt() return nil diff --git a/ent/perm.go b/ent/perm.go index f3b7aaeb..59065bd7 100644 --- a/ent/perm.go +++ b/ent/perm.go @@ -20,6 +20,8 @@ type Perm struct { ID int `json:"id,omitempty"` // RepoPerm holds the value of the "repo_perm" field. RepoPerm perm.RepoPerm `json:"repo_perm"` + // SyncedAt holds the value of the "synced_at" field. + SyncedAt time.Time `json:"synced_at"` // CreatedAt holds the value of the "created_at" field. CreatedAt time.Time `json:"created_at"` // UpdatedAt holds the value of the "updated_at" field. @@ -81,7 +83,7 @@ func (*Perm) scanValues(columns []string) ([]interface{}, error) { values[i] = new(sql.NullInt64) case perm.FieldRepoPerm: values[i] = new(sql.NullString) - case perm.FieldCreatedAt, perm.FieldUpdatedAt: + case perm.FieldSyncedAt, perm.FieldCreatedAt, perm.FieldUpdatedAt: values[i] = new(sql.NullTime) default: return nil, fmt.Errorf("unexpected column %q for type Perm", columns[i]) @@ -110,6 +112,12 @@ func (pe *Perm) assignValues(columns []string, values []interface{}) error { } else if value.Valid { pe.RepoPerm = perm.RepoPerm(value.String) } + case perm.FieldSyncedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field synced_at", values[i]) + } else if value.Valid { + pe.SyncedAt = value.Time + } case perm.FieldCreatedAt: if value, ok := values[i].(*sql.NullTime); !ok { return fmt.Errorf("unexpected type %T for field created_at", values[i]) @@ -174,6 +182,8 @@ func (pe *Perm) String() string { builder.WriteString(fmt.Sprintf("id=%v", pe.ID)) builder.WriteString(", repo_perm=") builder.WriteString(fmt.Sprintf("%v", pe.RepoPerm)) + builder.WriteString(", synced_at=") + builder.WriteString(pe.SyncedAt.Format(time.ANSIC)) builder.WriteString(", created_at=") builder.WriteString(pe.CreatedAt.Format(time.ANSIC)) builder.WriteString(", updated_at=") diff --git a/ent/perm/perm.go b/ent/perm/perm.go index 22a2a963..f84008d9 100644 --- a/ent/perm/perm.go +++ b/ent/perm/perm.go @@ -14,6 +14,8 @@ const ( FieldID = "id" // FieldRepoPerm holds the string denoting the repo_perm field in the database. FieldRepoPerm = "repo_perm" + // FieldSyncedAt holds the string denoting the synced_at field in the database. + FieldSyncedAt = "synced_at" // FieldCreatedAt holds the string denoting the created_at field in the database. FieldCreatedAt = "created_at" // FieldUpdatedAt holds the string denoting the updated_at field in the database. @@ -48,6 +50,7 @@ const ( var Columns = []string{ FieldID, FieldRepoPerm, + FieldSyncedAt, FieldCreatedAt, FieldUpdatedAt, FieldUserID, diff --git a/ent/perm/where.go b/ent/perm/where.go index 70a82645..643823e4 100644 --- a/ent/perm/where.go +++ b/ent/perm/where.go @@ -93,6 +93,13 @@ func IDLTE(id int) predicate.Perm { }) } +// SyncedAt applies equality check predicate on the "synced_at" field. It's identical to SyncedAtEQ. +func SyncedAt(v time.Time) predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldSyncedAt), v)) + }) +} + // CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. func CreatedAt(v time.Time) predicate.Perm { return predicate.Perm(func(s *sql.Selector) { @@ -169,6 +176,82 @@ func RepoPermNotIn(vs ...RepoPerm) predicate.Perm { }) } +// SyncedAtEQ applies the EQ predicate on the "synced_at" field. +func SyncedAtEQ(v time.Time) predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldSyncedAt), v)) + }) +} + +// SyncedAtNEQ applies the NEQ predicate on the "synced_at" field. +func SyncedAtNEQ(v time.Time) predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldSyncedAt), v)) + }) +} + +// SyncedAtIn applies the In predicate on the "synced_at" field. +func SyncedAtIn(vs ...time.Time) predicate.Perm { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Perm(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldSyncedAt), v...)) + }) +} + +// SyncedAtNotIn applies the NotIn predicate on the "synced_at" field. +func SyncedAtNotIn(vs ...time.Time) predicate.Perm { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Perm(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldSyncedAt), v...)) + }) +} + +// SyncedAtGT applies the GT predicate on the "synced_at" field. +func SyncedAtGT(v time.Time) predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldSyncedAt), v)) + }) +} + +// SyncedAtGTE applies the GTE predicate on the "synced_at" field. +func SyncedAtGTE(v time.Time) predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldSyncedAt), v)) + }) +} + +// SyncedAtLT applies the LT predicate on the "synced_at" field. +func SyncedAtLT(v time.Time) predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldSyncedAt), v)) + }) +} + +// SyncedAtLTE applies the LTE predicate on the "synced_at" field. +func SyncedAtLTE(v time.Time) predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldSyncedAt), v)) + }) +} + // CreatedAtEQ applies the EQ predicate on the "created_at" field. func CreatedAtEQ(v time.Time) predicate.Perm { return predicate.Perm(func(s *sql.Selector) { diff --git a/ent/perm_create.go b/ent/perm_create.go index f9bd0c52..e4b84101 100644 --- a/ent/perm_create.go +++ b/ent/perm_create.go @@ -36,6 +36,12 @@ func (pc *PermCreate) SetNillableRepoPerm(pp *perm.RepoPerm) *PermCreate { return pc } +// SetSyncedAt sets the "synced_at" field. +func (pc *PermCreate) SetSyncedAt(t time.Time) *PermCreate { + pc.mutation.SetSyncedAt(t) + return pc +} + // SetCreatedAt sets the "created_at" field. func (pc *PermCreate) SetCreatedAt(t time.Time) *PermCreate { pc.mutation.SetCreatedAt(t) @@ -181,6 +187,9 @@ func (pc *PermCreate) check() error { return &ValidationError{Name: "repo_perm", err: fmt.Errorf(`ent: validator failed for field "repo_perm": %w`, err)} } } + if _, ok := pc.mutation.SyncedAt(); !ok { + return &ValidationError{Name: "synced_at", err: errors.New(`ent: missing required field "synced_at"`)} + } if _, ok := pc.mutation.CreatedAt(); !ok { return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "created_at"`)} } @@ -234,6 +243,14 @@ func (pc *PermCreate) createSpec() (*Perm, *sqlgraph.CreateSpec) { }) _node.RepoPerm = value } + if value, ok := pc.mutation.SyncedAt(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: perm.FieldSyncedAt, + }) + _node.SyncedAt = value + } if value, ok := pc.mutation.CreatedAt(); ok { _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ Type: field.TypeTime, diff --git a/ent/perm_update.go b/ent/perm_update.go index 5807d5ee..45c4f026 100644 --- a/ent/perm_update.go +++ b/ent/perm_update.go @@ -44,6 +44,12 @@ func (pu *PermUpdate) SetNillableRepoPerm(pp *perm.RepoPerm) *PermUpdate { return pu } +// SetSyncedAt sets the "synced_at" field. +func (pu *PermUpdate) SetSyncedAt(t time.Time) *PermUpdate { + pu.mutation.SetSyncedAt(t) + return pu +} + // SetCreatedAt sets the "created_at" field. func (pu *PermUpdate) SetCreatedAt(t time.Time) *PermUpdate { pu.mutation.SetCreatedAt(t) @@ -213,6 +219,13 @@ func (pu *PermUpdate) sqlSave(ctx context.Context) (n int, err error) { Column: perm.FieldRepoPerm, }) } + if value, ok := pu.mutation.SyncedAt(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: perm.FieldSyncedAt, + }) + } if value, ok := pu.mutation.CreatedAt(); ok { _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ Type: field.TypeTime, @@ -330,6 +343,12 @@ func (puo *PermUpdateOne) SetNillableRepoPerm(pp *perm.RepoPerm) *PermUpdateOne return puo } +// SetSyncedAt sets the "synced_at" field. +func (puo *PermUpdateOne) SetSyncedAt(t time.Time) *PermUpdateOne { + puo.mutation.SetSyncedAt(t) + return puo +} + // SetCreatedAt sets the "created_at" field. func (puo *PermUpdateOne) SetCreatedAt(t time.Time) *PermUpdateOne { puo.mutation.SetCreatedAt(t) @@ -523,6 +542,13 @@ func (puo *PermUpdateOne) sqlSave(ctx context.Context) (_node *Perm, err error) Column: perm.FieldRepoPerm, }) } + if value, ok := puo.mutation.SyncedAt(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: perm.FieldSyncedAt, + }) + } if value, ok := puo.mutation.CreatedAt(); ok { _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ Type: field.TypeTime, diff --git a/ent/runtime.go b/ent/runtime.go index 4e20eea6..134170d5 100644 --- a/ent/runtime.go +++ b/ent/runtime.go @@ -117,11 +117,11 @@ func init() { permFields := schema.Perm{}.Fields() _ = permFields // permDescCreatedAt is the schema descriptor for created_at field. - permDescCreatedAt := permFields[1].Descriptor() + permDescCreatedAt := permFields[2].Descriptor() // perm.DefaultCreatedAt holds the default value on creation for the created_at field. perm.DefaultCreatedAt = permDescCreatedAt.Default.(func() time.Time) // permDescUpdatedAt is the schema descriptor for updated_at field. - permDescUpdatedAt := permFields[2].Descriptor() + permDescUpdatedAt := permFields[3].Descriptor() // perm.DefaultUpdatedAt holds the default value on creation for the updated_at field. perm.DefaultUpdatedAt = permDescUpdatedAt.Default.(func() time.Time) // perm.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. diff --git a/ent/schema/perm.go b/ent/schema/perm.go index b13b71e4..131d3ee6 100644 --- a/ent/schema/perm.go +++ b/ent/schema/perm.go @@ -24,6 +24,7 @@ func (Perm) Fields() []ent.Field { "admin", ). Default("read"), + field.Time("synced_at"), field.Time("created_at"). Default(time.Now), field.Time("updated_at"). @@ -56,6 +57,6 @@ func (Perm) Indexes() []ent.Index { // Find the perm for the repository. index.Fields("repo_id", "user_id"), // Delete staled perms after synchronization - index.Fields("user_id", "updated_at"), + index.Fields("user_id", "synced_at"), } } From a4e82e521f4aa9b8736780eba83179aee4a7ff0b Mon Sep 17 00:00:00 2001 From: noah Date: Mon, 4 Oct 2021 23:12:33 +0900 Subject: [PATCH 2/5] Fix to compare by synced_at when it deletes --- internal/interactor/interface.go | 2 +- internal/interactor/mock/pkg.go | 12 +++--- internal/pkg/store/perm.go | 4 +- internal/pkg/store/perm_test.go | 41 +++++++++++++------ internal/server/api/v1/sync/interface.go | 3 +- .../server/api/v1/sync/mock/interactor.go | 12 +++--- internal/server/api/v1/sync/syncher.go | 2 +- internal/server/api/v1/sync/syncher_test.go | 2 +- 8 files changed, 47 insertions(+), 31 deletions(-) diff --git a/internal/interactor/interface.go b/internal/interactor/interface.go index 2e0025f2..f61bf8c0 100644 --- a/internal/interactor/interface.go +++ b/internal/interactor/interface.go @@ -41,7 +41,7 @@ type ( FindPermOfRepo(ctx context.Context, r *ent.Repo, u *ent.User) (*ent.Perm, error) CreatePerm(ctx context.Context, p *ent.Perm) (*ent.Perm, error) UpdatePerm(ctx context.Context, p *ent.Perm) (*ent.Perm, error) - DeletePermsOfUserLessThanUpdatedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) + DeletePermsOfUserLessThanSyncedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) SearchDeployments(ctx context.Context, u *ent.User, s []deployment.Status, owned bool, from time.Time, to time.Time, page, perPage int) ([]*ent.Deployment, error) ListInactiveDeploymentsLessThanTime(ctx context.Context, t time.Time, page, perPage int) ([]*ent.Deployment, error) diff --git a/internal/interactor/mock/pkg.go b/internal/interactor/mock/pkg.go index c2dc4b2a..c8ab40b0 100644 --- a/internal/interactor/mock/pkg.go +++ b/internal/interactor/mock/pkg.go @@ -275,19 +275,19 @@ func (mr *MockStoreMockRecorder) DeleteLock(ctx, l interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteLock", reflect.TypeOf((*MockStore)(nil).DeleteLock), ctx, l) } -// DeletePermsOfUserLessThanUpdatedAt mocks base method. -func (m *MockStore) DeletePermsOfUserLessThanUpdatedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) { +// DeletePermsOfUserLessThanSyncedAt mocks base method. +func (m *MockStore) DeletePermsOfUserLessThanSyncedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeletePermsOfUserLessThanUpdatedAt", ctx, u, t) + ret := m.ctrl.Call(m, "DeletePermsOfUserLessThanSyncedAt", ctx, u, t) ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } -// DeletePermsOfUserLessThanUpdatedAt indicates an expected call of DeletePermsOfUserLessThanUpdatedAt. -func (mr *MockStoreMockRecorder) DeletePermsOfUserLessThanUpdatedAt(ctx, u, t interface{}) *gomock.Call { +// DeletePermsOfUserLessThanSyncedAt indicates an expected call of DeletePermsOfUserLessThanSyncedAt. +func (mr *MockStoreMockRecorder) DeletePermsOfUserLessThanSyncedAt(ctx, u, t interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePermsOfUserLessThanUpdatedAt", reflect.TypeOf((*MockStore)(nil).DeletePermsOfUserLessThanUpdatedAt), ctx, u, t) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePermsOfUserLessThanSyncedAt", reflect.TypeOf((*MockStore)(nil).DeletePermsOfUserLessThanSyncedAt), ctx, u, t) } // DeleteUser mocks base method. diff --git a/internal/pkg/store/perm.go b/internal/pkg/store/perm.go index b331e92a..50909e93 100644 --- a/internal/pkg/store/perm.go +++ b/internal/pkg/store/perm.go @@ -56,7 +56,7 @@ func (s *Store) UpdatePerm(ctx context.Context, p *ent.Perm) (*ent.Perm, error) Save(ctx) } -func (s *Store) DeletePermsOfUserLessThanUpdatedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) { +func (s *Store) DeletePermsOfUserLessThanSyncedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) { var ( cnt int err error @@ -68,7 +68,7 @@ func (s *Store) DeletePermsOfUserLessThanUpdatedAt(ctx context.Context, u *ent.U Where( perm.And( perm.UserIDEQ(u.ID), - perm.UpdatedAtLT(t), + perm.SyncedAtLT(t), ), ). Exec(ctx) diff --git a/internal/pkg/store/perm_test.go b/internal/pkg/store/perm_test.go index e97e570c..0da4ad4f 100644 --- a/internal/pkg/store/perm_test.go +++ b/internal/pkg/store/perm_test.go @@ -11,7 +11,7 @@ import ( "github.com/gitploy-io/gitploy/ent/perm" ) -func TestStore_DeletePermsOfUserLessThanUpdatedAt(t *testing.T) { +func TestStore_DeletePermsOfUserLessThanSyncedAt(t *testing.T) { client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1", enttest.WithMigrateOptions(migrate.WithForeignKeys(false)), ) @@ -20,7 +20,8 @@ func TestStore_DeletePermsOfUserLessThanUpdatedAt(t *testing.T) { const ( u1 = 1 u2 = 2 - r = 1 + r1 = 1 + r2 = 2 ) nor := time.Now() @@ -29,39 +30,55 @@ func TestStore_DeletePermsOfUserLessThanUpdatedAt(t *testing.T) { client.Perm. Create(). SetRepoPerm(perm.RepoPermWrite). + SetSyncedAt(nor.Add(-1 * time.Hour)). SetUserID(u1). - SetRepoID(r). - SetUpdatedAt(nor.Add(-1 * time.Hour)). + SetRepoID(r1). SaveX(context.Background()) client.Perm. Create(). SetRepoPerm(perm.RepoPermWrite). + SetSyncedAt(nor.Add(-1 * time.Hour)). + SetUserID(u1). + SetRepoID(r2). + SaveX(context.Background()) + + client.Perm. + Create(). + SetRepoPerm(perm.RepoPermWrite). + SetSyncedAt(nor.Add(-1 * time.Hour)). SetUserID(u2). - SetRepoID(r). - SetUpdatedAt(nor.Add(-1 * time.Hour)). + SetRepoID(r1). SaveX(context.Background()) t.Log("Insert new perms") client.Perm. Create(). SetRepoPerm(perm.RepoPermWrite). + SetSyncedAt(nor.Add(time.Hour)). SetUserID(u1). - SetRepoID(r). - SetUpdatedAt(nor.Add(time.Hour)). + SetRepoID(r1). + SaveX(context.Background()) + + client.Perm. + Create(). + SetRepoPerm(perm.RepoPermWrite). + SetSyncedAt(nor.Add(time.Hour)). + SetUserID(u2). + SetRepoID(r1). SaveX(context.Background()) t.Run("Delete staled perms.", func(t *testing.T) { s := NewStore(client) - cnt, err := s.DeletePermsOfUserLessThanUpdatedAt(context.Background(), &ent.User{ID: u1}, nor) + cnt, err := s.DeletePermsOfUserLessThanSyncedAt(context.Background(), &ent.User{ID: u1}, nor) if err != nil { - t.Fatalf("DeletePermsOfUserLessThanUpdatedAt returns an error: %s", err) + t.Fatalf("DeletePermsOfUserLessThanSyncedAt returns an error: %s", err) } - expected := 1 + expected := 2 if cnt != expected { - t.Fatalf("DeletePermsOfUserLessThanUpdatedAt = %v: %v", cnt, expected) + t.Fatalf("DeletePermsOfUserLessThanSyncedAt = %v: %v", cnt, expected) } }) } diff --git a/internal/server/api/v1/sync/interface.go b/internal/server/api/v1/sync/interface.go index ba07dade..9e9954e2 100644 --- a/internal/server/api/v1/sync/interface.go +++ b/internal/server/api/v1/sync/interface.go @@ -14,7 +14,6 @@ type ( Interactor interface { ListRemoteRepos(ctx context.Context, u *ent.User) ([]*vo.RemoteRepo, error) IsEntryOrg(ctx context.Context, namespace string) bool - SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.RemoteRepo) error - DeletePermsOfUserLessThanUpdatedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) + DeletePermsOfUserLessThanSyncedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) } ) diff --git a/internal/server/api/v1/sync/mock/interactor.go b/internal/server/api/v1/sync/mock/interactor.go index 6cadd7e7..6ccc299e 100644 --- a/internal/server/api/v1/sync/mock/interactor.go +++ b/internal/server/api/v1/sync/mock/interactor.go @@ -37,19 +37,19 @@ func (m *MockInteractor) EXPECT() *MockInteractorMockRecorder { return m.recorder } -// DeletePermsOfUserLessThanUpdatedAt mocks base method. -func (m *MockInteractor) DeletePermsOfUserLessThanUpdatedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) { +// DeletePermsOfUserLessThanSyncedAt mocks base method. +func (m *MockInteractor) DeletePermsOfUserLessThanSyncedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeletePermsOfUserLessThanUpdatedAt", ctx, u, t) + ret := m.ctrl.Call(m, "DeletePermsOfUserLessThanSyncedAt", ctx, u, t) ret0, _ := ret[0].(int) ret1, _ := ret[1].(error) return ret0, ret1 } -// DeletePermsOfUserLessThanUpdatedAt indicates an expected call of DeletePermsOfUserLessThanUpdatedAt. -func (mr *MockInteractorMockRecorder) DeletePermsOfUserLessThanUpdatedAt(ctx, u, t interface{}) *gomock.Call { +// DeletePermsOfUserLessThanSyncedAt indicates an expected call of DeletePermsOfUserLessThanSyncedAt. +func (mr *MockInteractorMockRecorder) DeletePermsOfUserLessThanSyncedAt(ctx, u, t interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePermsOfUserLessThanUpdatedAt", reflect.TypeOf((*MockInteractor)(nil).DeletePermsOfUserLessThanUpdatedAt), ctx, u, t) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePermsOfUserLessThanSyncedAt", reflect.TypeOf((*MockInteractor)(nil).DeletePermsOfUserLessThanSyncedAt), ctx, u, t) } // IsEntryOrg mocks base method. diff --git a/internal/server/api/v1/sync/syncher.go b/internal/server/api/v1/sync/syncher.go index 25864bf8..51e08a0f 100644 --- a/internal/server/api/v1/sync/syncher.go +++ b/internal/server/api/v1/sync/syncher.go @@ -61,7 +61,7 @@ func (s *Syncher) Sync(c *gin.Context) { // Delete staled perms. var cnt int - if cnt, err = s.i.DeletePermsOfUserLessThanUpdatedAt(ctx, u, syncTime); err != nil { + if cnt, err = s.i.DeletePermsOfUserLessThanSyncedAt(ctx, u, syncTime); err != nil { s.log.Error("It has failed to delete staled repositories.", zap.Error(err)) gb.ErrorResponse(c, http.StatusInternalServerError, "It has failed to delete staled repositories.") return diff --git a/internal/server/api/v1/sync/syncher_test.go b/internal/server/api/v1/sync/syncher_test.go index f14bc1c4..4d150137 100644 --- a/internal/server/api/v1/sync/syncher_test.go +++ b/internal/server/api/v1/sync/syncher_test.go @@ -60,7 +60,7 @@ func TestSyncher_Sync(t *testing.T) { t.Log("Delete staled perms.") m. EXPECT(). - DeletePermsOfUserLessThanUpdatedAt(ctx, gomock.Any(), gomock.Any()). + DeletePermsOfUserLessThanSyncedAt(ctx, gomock.Any(), gomock.Any()). Return(0, nil) gin.SetMode(gin.ReleaseMode) From b828a61250262a1216530b77e329768c20b7f744 Mon Sep 17 00:00:00 2001 From: noah Date: Mon, 4 Oct 2021 23:14:07 +0900 Subject: [PATCH 3/5] Fix to set synced_at when it sync --- internal/interactor/sync.go | 5 +- internal/interactor/sync_test.go | 54 +++++++++++++++++- internal/pkg/store/perm.go | 2 + internal/pkg/store/perm_test.go | 57 +++++++++++++++++++ internal/server/api/v1/sync/interface.go | 1 + .../server/api/v1/sync/mock/interactor.go | 8 +-- internal/server/api/v1/sync/syncher.go | 2 +- internal/server/api/v1/sync/syncher_test.go | 3 +- 8 files changed, 124 insertions(+), 8 deletions(-) diff --git a/internal/interactor/sync.go b/internal/interactor/sync.go index 81d20f79..fbfb693c 100644 --- a/internal/interactor/sync.go +++ b/internal/interactor/sync.go @@ -2,6 +2,7 @@ package interactor import ( "context" + "time" "github.com/gitploy-io/gitploy/ent" "github.com/gitploy-io/gitploy/ent/perm" @@ -22,7 +23,7 @@ func (i *Interactor) IsEntryOrg(ctx context.Context, namespace string) bool { return false } -func (i *Interactor) SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.RemoteRepo) error { +func (i *Interactor) SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.RemoteRepo, t time.Time) error { var ( r *ent.Repo p *ent.Perm @@ -42,6 +43,7 @@ func (i *Interactor) SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.Rem RepoPerm: perm.RepoPerm(re.Perm), UserID: u.ID, RepoID: r.ID, + SyncedAt: t, }); err != nil { return err } @@ -49,6 +51,7 @@ func (i *Interactor) SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.Rem return err } else { p.RepoPerm = perm.RepoPerm(re.Perm) + p.SyncedAt = t if _, err = i.Store.UpdatePerm(ctx, p); err != nil { return err diff --git a/internal/interactor/sync_test.go b/internal/interactor/sync_test.go index bb563506..8b8aaf2f 100644 --- a/internal/interactor/sync_test.go +++ b/internal/interactor/sync_test.go @@ -3,6 +3,7 @@ package interactor import ( "context" "testing" + "time" "github.com/gitploy-io/gitploy/ent" "github.com/gitploy-io/gitploy/ent/perm" @@ -18,6 +19,7 @@ func TestInteractor_SyncRemoteRepo(t *testing.T) { input := struct { user *ent.User remote *vo.RemoteRepo + time time.Time }{ user: &ent.User{ ID: 2214, @@ -26,6 +28,7 @@ func TestInteractor_SyncRemoteRepo(t *testing.T) { ID: 2214, Perm: vo.RemoteRepoPermRead, }, + time: time.Now(), } ctrl := gomock.NewController(t) @@ -58,13 +61,62 @@ func TestInteractor_SyncRemoteRepo(t *testing.T) { RepoPerm: perm.RepoPerm(input.remote.Perm), UserID: input.user.ID, RepoID: input.remote.ID, + SyncedAt: input.time, })). DoAndReturn(func(ctx context.Context, p *ent.Perm) (*ent.Perm, error) { return p, nil }) i := &Interactor{Store: store} - if err := i.SyncRemoteRepo(context.Background(), input.user, input.remote); err != nil { + if err := i.SyncRemoteRepo(context.Background(), input.user, input.remote, input.time); err != nil { + t.Fatal("SyncRemoteRepo returns error.") + } + }) + + t.Run("Synchronization updates the perm if it exist.", func(t *testing.T) { + input := struct { + user *ent.User + remote *vo.RemoteRepo + time time.Time + }{ + user: &ent.User{ + ID: 1, + }, + remote: &vo.RemoteRepo{ + ID: 1, + Perm: vo.RemoteRepoPermWrite, + }, + time: time.Now(), + } + + ctrl := gomock.NewController(t) + store := mock.NewMockStore(ctrl) + + t.Log("The repo is found.") + store. + EXPECT(). + FindRepoByID(ctx, input.remote.ID). + Return(&ent.Repo{ID: input.remote.ID}, nil) + + t.Log("The perm is found.") + store. + EXPECT(). + FindPermOfRepo(ctx, gomock.Eq(&ent.Repo{ID: input.remote.ID}), gomock.Eq(input.user)). + Return(&ent.Perm{}, nil) + + t.Log("Update the perm with perm, and synced_at.") + store. + EXPECT(). + UpdatePerm(ctx, gomock.Eq(&ent.Perm{ + RepoPerm: perm.RepoPerm(input.remote.Perm), + SyncedAt: input.time, + })). + DoAndReturn(func(ctx context.Context, p *ent.Perm) (*ent.Perm, error) { + return p, nil + }) + + i := &Interactor{Store: store} + if err := i.SyncRemoteRepo(context.Background(), input.user, input.remote, input.time); err != nil { t.Fatal("SyncRemoteRepo returns error.") } }) diff --git a/internal/pkg/store/perm.go b/internal/pkg/store/perm.go index 50909e93..733576fb 100644 --- a/internal/pkg/store/perm.go +++ b/internal/pkg/store/perm.go @@ -44,6 +44,7 @@ func (s *Store) CreatePerm(ctx context.Context, p *ent.Perm) (*ent.Perm, error) return s.c.Perm. Create(). SetRepoPerm(p.RepoPerm). + SetSyncedAt(p.SyncedAt). SetUserID(p.UserID). SetRepoID(p.RepoID). Save(ctx) @@ -53,6 +54,7 @@ func (s *Store) UpdatePerm(ctx context.Context, p *ent.Perm) (*ent.Perm, error) return s.c.Perm. UpdateOne(p). SetRepoPerm(p.RepoPerm). + SetSyncedAt(p.SyncedAt). Save(ctx) } diff --git a/internal/pkg/store/perm_test.go b/internal/pkg/store/perm_test.go index 0da4ad4f..dcd9fcba 100644 --- a/internal/pkg/store/perm_test.go +++ b/internal/pkg/store/perm_test.go @@ -11,6 +11,63 @@ import ( "github.com/gitploy-io/gitploy/ent/perm" ) +func TestStore_CreatePerm(t *testing.T) { + t.Run("Create a new perm", func(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1", + enttest.WithMigrateOptions(migrate.WithForeignKeys(false)), + ) + defer client.Close() + + s := NewStore(client) + + _, err := s.CreatePerm(context.Background(), &ent.Perm{ + RepoPerm: perm.DefaultRepoPerm, + SyncedAt: time.Now(), + UserID: 1, + RepoID: 1, + }) + if err != nil { + t.Fatalf("CreatePerm returns an error: %s", err) + } + }) +} + +func TestStore_UpdatePerm(t *testing.T) { + t.Run("Update the perm", func(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1", + enttest.WithMigrateOptions(migrate.WithForeignKeys(false)), + ) + defer client.Close() + + t.Log("Insert a perm") + p := client.Perm. + Create(). + SetRepoPerm(perm.RepoPermRead). + SetSyncedAt(time.Now().Add(-time.Hour)). + SetUserID(1). + SetRepoID(1). + SaveX(context.Background()) + + t.Log("Update the perm") + syncedAt := time.Now() + + p.RepoPerm = perm.RepoPermWrite + p.SyncedAt = syncedAt + + s := NewStore(client) + + n, err := s.UpdatePerm(context.Background(), p) + if err != nil { + t.Fatalf("UpdatePerm returns an error: %s", err) + } + + if !(n.RepoPerm == p.RepoPerm && n.SyncedAt.Equal(p.SyncedAt)) { + t.Log("Values, perm and synced_at, is not equal.") + t.Fatalf("UpdatePerm = %v, wanted %v", n, p) + } + }) +} + func TestStore_DeletePermsOfUserLessThanSyncedAt(t *testing.T) { client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1", enttest.WithMigrateOptions(migrate.WithForeignKeys(false)), diff --git a/internal/server/api/v1/sync/interface.go b/internal/server/api/v1/sync/interface.go index 9e9954e2..940f18f6 100644 --- a/internal/server/api/v1/sync/interface.go +++ b/internal/server/api/v1/sync/interface.go @@ -14,6 +14,7 @@ type ( Interactor interface { ListRemoteRepos(ctx context.Context, u *ent.User) ([]*vo.RemoteRepo, error) IsEntryOrg(ctx context.Context, namespace string) bool + SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.RemoteRepo, t time.Time) error DeletePermsOfUserLessThanSyncedAt(ctx context.Context, u *ent.User, t time.Time) (int, error) } ) diff --git a/internal/server/api/v1/sync/mock/interactor.go b/internal/server/api/v1/sync/mock/interactor.go index 6ccc299e..c2fe3ba5 100644 --- a/internal/server/api/v1/sync/mock/interactor.go +++ b/internal/server/api/v1/sync/mock/interactor.go @@ -82,15 +82,15 @@ func (mr *MockInteractorMockRecorder) ListRemoteRepos(ctx, u interface{}) *gomoc } // SyncRemoteRepo mocks base method. -func (m *MockInteractor) SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.RemoteRepo) error { +func (m *MockInteractor) SyncRemoteRepo(ctx context.Context, u *ent.User, re *vo.RemoteRepo, t time.Time) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SyncRemoteRepo", ctx, u, re) + ret := m.ctrl.Call(m, "SyncRemoteRepo", ctx, u, re, t) ret0, _ := ret[0].(error) return ret0 } // SyncRemoteRepo indicates an expected call of SyncRemoteRepo. -func (mr *MockInteractorMockRecorder) SyncRemoteRepo(ctx, u, re interface{}) *gomock.Call { +func (mr *MockInteractorMockRecorder) SyncRemoteRepo(ctx, u, re, t interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncRemoteRepo", reflect.TypeOf((*MockInteractor)(nil).SyncRemoteRepo), ctx, u, re) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncRemoteRepo", reflect.TypeOf((*MockInteractor)(nil).SyncRemoteRepo), ctx, u, re, t) } diff --git a/internal/server/api/v1/sync/syncher.go b/internal/server/api/v1/sync/syncher.go index 51e08a0f..291f8d29 100644 --- a/internal/server/api/v1/sync/syncher.go +++ b/internal/server/api/v1/sync/syncher.go @@ -51,7 +51,7 @@ func (s *Syncher) Sync(c *gin.Context) { continue } - if err := s.i.SyncRemoteRepo(ctx, u, re); err != nil { + if err := s.i.SyncRemoteRepo(ctx, u, re, syncTime); err != nil { s.log.Error("It has failed to sync with the remote repository.", zap.Error(err), zap.Int64("repo_id", re.ID)) continue } diff --git a/internal/server/api/v1/sync/syncher_test.go b/internal/server/api/v1/sync/syncher_test.go index 4d150137..500d329d 100644 --- a/internal/server/api/v1/sync/syncher_test.go +++ b/internal/server/api/v1/sync/syncher_test.go @@ -5,6 +5,7 @@ import ( "net/http" "net/http/httptest" "testing" + "time" "github.com/gin-gonic/gin" "github.com/gitploy-io/gitploy/ent" @@ -54,7 +55,7 @@ func TestSyncher_Sync(t *testing.T) { ID: 1, Namespace: "octocat", Name: "HelloWorld", - })). + }), gomock.AssignableToTypeOf(&time.Time{})). Return(nil) t.Log("Delete staled perms.") From 61c6dbd78028d59703582813ccae85a2f0095222 Mon Sep 17 00:00:00 2001 From: noah Date: Mon, 4 Oct 2021 23:30:43 +0900 Subject: [PATCH 4/5] Fix synced_at field optional for schema migration --- ent/migrate/schema.go | 2 +- ent/mutation.go | 24 +++++++++++++++++++- ent/perm.go | 2 +- ent/perm/where.go | 14 ++++++++++++ ent/perm_create.go | 11 ++++++--- ent/perm_update.go | 40 +++++++++++++++++++++++++++++++++ ent/schema/perm.go | 3 ++- internal/pkg/store/perm.go | 12 +++++++--- internal/pkg/store/perm_test.go | 9 +++++++- 9 files changed, 106 insertions(+), 11 deletions(-) diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 8dd24279..32215ac4 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -275,7 +275,7 @@ var ( PermsColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, {Name: "repo_perm", Type: field.TypeEnum, Enums: []string{"read", "write", "admin"}, Default: "read"}, - {Name: "synced_at", Type: field.TypeTime}, + {Name: "synced_at", Type: field.TypeTime, Nullable: true}, {Name: "created_at", Type: field.TypeTime}, {Name: "updated_at", Type: field.TypeTime}, {Name: "repo_id", Type: field.TypeInt64, Nullable: true}, diff --git a/ent/mutation.go b/ent/mutation.go index 46041ec8..f5d06da3 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -6098,9 +6098,22 @@ func (m *PermMutation) OldSyncedAt(ctx context.Context) (v time.Time, err error) return oldValue.SyncedAt, nil } +// ClearSyncedAt clears the value of the "synced_at" field. +func (m *PermMutation) ClearSyncedAt() { + m.synced_at = nil + m.clearedFields[perm.FieldSyncedAt] = struct{}{} +} + +// SyncedAtCleared returns if the "synced_at" field was cleared in this mutation. +func (m *PermMutation) SyncedAtCleared() bool { + _, ok := m.clearedFields[perm.FieldSyncedAt] + return ok +} + // ResetSyncedAt resets all changes to the "synced_at" field. func (m *PermMutation) ResetSyncedAt() { m.synced_at = nil + delete(m.clearedFields, perm.FieldSyncedAt) } // SetCreatedAt sets the "created_at" field. @@ -6461,7 +6474,11 @@ func (m *PermMutation) AddField(name string, value ent.Value) error { // ClearedFields returns all nullable fields that were cleared during this // mutation. func (m *PermMutation) ClearedFields() []string { - return nil + var fields []string + if m.FieldCleared(perm.FieldSyncedAt) { + fields = append(fields, perm.FieldSyncedAt) + } + return fields } // FieldCleared returns a boolean indicating if a field with the given name was @@ -6474,6 +6491,11 @@ func (m *PermMutation) FieldCleared(name string) bool { // ClearField clears the value of the field with the given name. It returns an // error if the field is not defined in the schema. func (m *PermMutation) ClearField(name string) error { + switch name { + case perm.FieldSyncedAt: + m.ClearSyncedAt() + return nil + } return fmt.Errorf("unknown Perm nullable field %s", name) } diff --git a/ent/perm.go b/ent/perm.go index 59065bd7..00918d0f 100644 --- a/ent/perm.go +++ b/ent/perm.go @@ -21,7 +21,7 @@ type Perm struct { // RepoPerm holds the value of the "repo_perm" field. RepoPerm perm.RepoPerm `json:"repo_perm"` // SyncedAt holds the value of the "synced_at" field. - SyncedAt time.Time `json:"synced_at"` + SyncedAt time.Time `json:"synced_at,omitemtpy"` // CreatedAt holds the value of the "created_at" field. CreatedAt time.Time `json:"created_at"` // UpdatedAt holds the value of the "updated_at" field. diff --git a/ent/perm/where.go b/ent/perm/where.go index 643823e4..d2ce2575 100644 --- a/ent/perm/where.go +++ b/ent/perm/where.go @@ -252,6 +252,20 @@ func SyncedAtLTE(v time.Time) predicate.Perm { }) } +// SyncedAtIsNil applies the IsNil predicate on the "synced_at" field. +func SyncedAtIsNil() predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.IsNull(s.C(FieldSyncedAt))) + }) +} + +// SyncedAtNotNil applies the NotNil predicate on the "synced_at" field. +func SyncedAtNotNil() predicate.Perm { + return predicate.Perm(func(s *sql.Selector) { + s.Where(sql.NotNull(s.C(FieldSyncedAt))) + }) +} + // CreatedAtEQ applies the EQ predicate on the "created_at" field. func CreatedAtEQ(v time.Time) predicate.Perm { return predicate.Perm(func(s *sql.Selector) { diff --git a/ent/perm_create.go b/ent/perm_create.go index e4b84101..2796a17e 100644 --- a/ent/perm_create.go +++ b/ent/perm_create.go @@ -42,6 +42,14 @@ func (pc *PermCreate) SetSyncedAt(t time.Time) *PermCreate { return pc } +// SetNillableSyncedAt sets the "synced_at" field if the given value is not nil. +func (pc *PermCreate) SetNillableSyncedAt(t *time.Time) *PermCreate { + if t != nil { + pc.SetSyncedAt(*t) + } + return pc +} + // SetCreatedAt sets the "created_at" field. func (pc *PermCreate) SetCreatedAt(t time.Time) *PermCreate { pc.mutation.SetCreatedAt(t) @@ -187,9 +195,6 @@ func (pc *PermCreate) check() error { return &ValidationError{Name: "repo_perm", err: fmt.Errorf(`ent: validator failed for field "repo_perm": %w`, err)} } } - if _, ok := pc.mutation.SyncedAt(); !ok { - return &ValidationError{Name: "synced_at", err: errors.New(`ent: missing required field "synced_at"`)} - } if _, ok := pc.mutation.CreatedAt(); !ok { return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "created_at"`)} } diff --git a/ent/perm_update.go b/ent/perm_update.go index 45c4f026..d7bf6984 100644 --- a/ent/perm_update.go +++ b/ent/perm_update.go @@ -50,6 +50,20 @@ func (pu *PermUpdate) SetSyncedAt(t time.Time) *PermUpdate { return pu } +// SetNillableSyncedAt sets the "synced_at" field if the given value is not nil. +func (pu *PermUpdate) SetNillableSyncedAt(t *time.Time) *PermUpdate { + if t != nil { + pu.SetSyncedAt(*t) + } + return pu +} + +// ClearSyncedAt clears the value of the "synced_at" field. +func (pu *PermUpdate) ClearSyncedAt() *PermUpdate { + pu.mutation.ClearSyncedAt() + return pu +} + // SetCreatedAt sets the "created_at" field. func (pu *PermUpdate) SetCreatedAt(t time.Time) *PermUpdate { pu.mutation.SetCreatedAt(t) @@ -226,6 +240,12 @@ func (pu *PermUpdate) sqlSave(ctx context.Context) (n int, err error) { Column: perm.FieldSyncedAt, }) } + if pu.mutation.SyncedAtCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Column: perm.FieldSyncedAt, + }) + } if value, ok := pu.mutation.CreatedAt(); ok { _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ Type: field.TypeTime, @@ -349,6 +369,20 @@ func (puo *PermUpdateOne) SetSyncedAt(t time.Time) *PermUpdateOne { return puo } +// SetNillableSyncedAt sets the "synced_at" field if the given value is not nil. +func (puo *PermUpdateOne) SetNillableSyncedAt(t *time.Time) *PermUpdateOne { + if t != nil { + puo.SetSyncedAt(*t) + } + return puo +} + +// ClearSyncedAt clears the value of the "synced_at" field. +func (puo *PermUpdateOne) ClearSyncedAt() *PermUpdateOne { + puo.mutation.ClearSyncedAt() + return puo +} + // SetCreatedAt sets the "created_at" field. func (puo *PermUpdateOne) SetCreatedAt(t time.Time) *PermUpdateOne { puo.mutation.SetCreatedAt(t) @@ -549,6 +583,12 @@ func (puo *PermUpdateOne) sqlSave(ctx context.Context) (_node *Perm, err error) Column: perm.FieldSyncedAt, }) } + if puo.mutation.SyncedAtCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Column: perm.FieldSyncedAt, + }) + } if value, ok := puo.mutation.CreatedAt(); ok { _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ Type: field.TypeTime, diff --git a/ent/schema/perm.go b/ent/schema/perm.go index 131d3ee6..73f1e014 100644 --- a/ent/schema/perm.go +++ b/ent/schema/perm.go @@ -24,7 +24,8 @@ func (Perm) Fields() []ent.Field { "admin", ). Default("read"), - field.Time("synced_at"), + field.Time("synced_at"). + Optional(), field.Time("created_at"). Default(time.Now), field.Time("updated_at"). diff --git a/internal/pkg/store/perm.go b/internal/pkg/store/perm.go index 733576fb..1807d351 100644 --- a/internal/pkg/store/perm.go +++ b/internal/pkg/store/perm.go @@ -68,9 +68,15 @@ func (s *Store) DeletePermsOfUserLessThanSyncedAt(ctx context.Context, u *ent.Us cnt, err = tx.Perm. Delete(). Where( - perm.And( - perm.UserIDEQ(u.ID), - perm.SyncedAtLT(t), + perm.Or( + perm.And( + perm.UserIDEQ(u.ID), + perm.SyncedAtLT(t), + ), + perm.And( + perm.UserIDEQ(u.ID), + perm.SyncedAtIsNil(), + ), ), ). Exec(ctx) diff --git a/internal/pkg/store/perm_test.go b/internal/pkg/store/perm_test.go index dcd9fcba..30d3cd5f 100644 --- a/internal/pkg/store/perm_test.go +++ b/internal/pkg/store/perm_test.go @@ -92,6 +92,13 @@ func TestStore_DeletePermsOfUserLessThanSyncedAt(t *testing.T) { SetRepoID(r1). SaveX(context.Background()) + client.Perm. + Create(). + SetRepoPerm(perm.RepoPermWrite). + SetUserID(u1). + SetRepoID(r1). + SaveX(context.Background()) + client.Perm. Create(). SetRepoPerm(perm.RepoPermWrite). @@ -133,7 +140,7 @@ func TestStore_DeletePermsOfUserLessThanSyncedAt(t *testing.T) { t.Fatalf("DeletePermsOfUserLessThanSyncedAt returns an error: %s", err) } - expected := 2 + expected := 3 if cnt != expected { t.Fatalf("DeletePermsOfUserLessThanSyncedAt = %v: %v", cnt, expected) } From c3a0713527244075e817b44392760474b8c1eb9b Mon Sep 17 00:00:00 2001 From: noah Date: Mon, 4 Oct 2021 23:38:47 +0900 Subject: [PATCH 5/5] Fix the error from test --- internal/server/api/v1/sync/syncher_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/server/api/v1/sync/syncher_test.go b/internal/server/api/v1/sync/syncher_test.go index 500d329d..8417179a 100644 --- a/internal/server/api/v1/sync/syncher_test.go +++ b/internal/server/api/v1/sync/syncher_test.go @@ -55,7 +55,7 @@ func TestSyncher_Sync(t *testing.T) { ID: 1, Namespace: "octocat", Name: "HelloWorld", - }), gomock.AssignableToTypeOf(&time.Time{})). + }), gomock.AssignableToTypeOf(time.Time{})). Return(nil) t.Log("Delete staled perms.")