diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 6b07a4fa8a0..7be970c8acb 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -281,7 +281,7 @@ func (hs *HTTPServer) deleteDashboard(c *models.ReqContext) response.Response { if hs.entityEventsService != nil { if err := hs.entityEventsService.SaveEvent(c.Req.Context(), store.SaveEventCmd{ - Grn: createDashboardGrn(dash.OrgId, dash.Uid), + EntityId: store.CreateDatabaseEntityId(dash.Uid, dash.OrgId, store.EntityTypeDashboard), EventType: store.EntityEventTypeDelete, }); err != nil { hs.log.Warn("failed to save dashboard entity event", "uid", dash.Uid, "error", err) @@ -301,10 +301,6 @@ func (hs *HTTPServer) deleteDashboard(c *models.ReqContext) response.Response { }) } -func createDashboardGrn(orgId int64, uid string) string { - return fmt.Sprintf("database/%d/dashboard/%s", orgId, uid) -} - func (hs *HTTPServer) PostDashboard(c *models.ReqContext) response.Response { cmd := models.SaveDashboardCommand{} if err := web.Bind(c.Req, &cmd); err != nil { @@ -379,7 +375,7 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa if dashboard != nil && hs.entityEventsService != nil { if err := hs.entityEventsService.SaveEvent(ctx, store.SaveEventCmd{ - Grn: createDashboardGrn(dashboard.OrgId, dashboard.Uid), + EntityId: store.CreateDatabaseEntityId(dashboard.Uid, dashboard.OrgId, store.EntityTypeDashboard), EventType: store.EntityEventTypeUpdate, }); err != nil { hs.log.Warn("failed to save dashboard entity event", "uid", dashboard.Uid, "error", err) diff --git a/pkg/services/searchV2/index.go b/pkg/services/searchV2/index.go index c6d83bcef6a..cafcf7a6524 100644 --- a/pkg/services/searchV2/index.go +++ b/pkg/services/searchV2/index.go @@ -139,25 +139,25 @@ func (i *dashboardIndex) applyIndexUpdates(ctx context.Context, lastEventID int6 } func (i *dashboardIndex) applyEventOnIndex(ctx context.Context, e *store.EntityEvent) error { - if !strings.HasPrefix(e.Grn, "database/") { - i.logger.Warn("unknown storage", "grn", e.Grn) + if !strings.HasPrefix(e.EntityId, "database/") { + i.logger.Warn("unknown storage", "entityId", e.EntityId) return nil } - parts := strings.Split(strings.TrimPrefix(e.Grn, "database/"), "/") + parts := strings.Split(strings.TrimPrefix(e.EntityId, "database/"), "/") if len(parts) != 3 { - i.logger.Error("can't parse GRN", "grn", e.Grn) + i.logger.Error("can't parse entityId", "entityId", e.EntityId) return nil } orgIDStr := parts[0] kind := parts[1] dashboardUID := parts[2] if kind != "dashboard" { - i.logger.Error("unknown kind in GRN", "grn", e.Grn) + i.logger.Error("unknown kind in entityId", "entityId", e.EntityId) return nil } orgID, err := strconv.Atoi(orgIDStr) if err != nil { - i.logger.Error("can't extract org ID", "grn", e.Grn) + i.logger.Error("can't extract org ID", "entityId", e.EntityId) return nil } return i.applyDashboardEvent(ctx, int64(orgID), dashboardUID, e.EventType) diff --git a/pkg/services/sqlstore/migrations/entity_events_mig.go b/pkg/services/sqlstore/migrations/entity_events_mig.go index 91934c8cb4e..c3b61e58239 100644 --- a/pkg/services/sqlstore/migrations/entity_events_mig.go +++ b/pkg/services/sqlstore/migrations/entity_events_mig.go @@ -7,7 +7,7 @@ func addEntityEventsTableMigration(mg *Migrator) { Name: "entity_event", Columns: []*Column{ {Name: "id", Type: DB_BigInt, Nullable: false, IsPrimaryKey: true, IsAutoIncrement: true}, - {Name: "grn", Type: DB_NVarchar, Length: 1024, Nullable: false}, + {Name: "entity_id", Type: DB_NVarchar, Length: 1024, Nullable: false}, {Name: "event_type", Type: DB_NVarchar, Length: 8, Nullable: false}, {Name: "created", Type: DB_BigInt, Nullable: false}, }, diff --git a/pkg/services/store/entity_events.go b/pkg/services/store/entity_events.go index c7b0ad08bd4..b56c98f5d92 100644 --- a/pkg/services/store/entity_events.go +++ b/pkg/services/store/entity_events.go @@ -2,6 +2,7 @@ package store import ( "context" + "fmt" "time" "github.com/grafana/grafana/pkg/infra/log" @@ -18,15 +19,34 @@ const ( EntityEventTypeUpdate EntityEventType = "update" ) +type EntityType string + +const ( + EntityTypeDashboard EntityType = "dashboard" +) + +// CreateDatabaseEntityId creates entityId for entities stored in the existing SQL tables +func CreateDatabaseEntityId(internalId interface{}, orgId int64, entityType EntityType) string { + var internalIdAsString string + switch id := internalId.(type) { + case string: + internalIdAsString = id + default: + internalIdAsString = fmt.Sprintf("%#v", internalId) + } + + return fmt.Sprintf("database/%d/%s/%s", orgId, entityType, internalIdAsString) +} + type EntityEvent struct { Id int64 EventType EntityEventType - Grn string + EntityId string Created int64 } type SaveEventCmd struct { - Grn string + EntityId string EventType EntityEventType } @@ -58,7 +78,7 @@ func (e *entityEventService) SaveEvent(ctx context.Context, cmd SaveEventCmd) er return e.sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { _, err := sess.Insert(&EntityEvent{ EventType: cmd.EventType, - Grn: cmd.Grn, + EntityId: cmd.EntityId, Created: time.Now().Unix(), }) return err diff --git a/pkg/services/store/entity_events_test.go b/pkg/services/store/entity_events_test.go index 2706f54d159..19d15a6b29a 100644 --- a/pkg/services/store/entity_events_test.go +++ b/pkg/services/store/entity_events_test.go @@ -30,7 +30,7 @@ func TestEntityEventsService(t *testing.T) { setup() err := service.SaveEvent(ctx, SaveEventCmd{ - Grn: "database/dash/1", + EntityId: "database/dash/1", EventType: EntityEventTypeCreate, }) require.NoError(t, err) @@ -46,35 +46,35 @@ func TestEntityEventsService(t *testing.T) { t.Run("Should retrieve last entity event", func(t *testing.T) { setup() - lastEventGrn := "database/dash/1" + lastEventEntityId := "database/dash/1" err := service.SaveEvent(ctx, SaveEventCmd{ - Grn: "database/dash/3", + EntityId: "database/dash/3", EventType: EntityEventTypeCreate, }) require.NoError(t, err) err = service.SaveEvent(ctx, SaveEventCmd{ - Grn: "database/dash/2", + EntityId: "database/dash/2", EventType: EntityEventTypeCreate, }) require.NoError(t, err) err = service.SaveEvent(ctx, SaveEventCmd{ - Grn: lastEventGrn, + EntityId: lastEventEntityId, EventType: EntityEventTypeCreate, }) require.NoError(t, err) lastEv, err := service.GetLastEvent(ctx) require.NoError(t, err) - require.Equal(t, lastEventGrn, lastEv.Grn) + require.Equal(t, lastEventEntityId, lastEv.EntityId) }) t.Run("Should retrieve sorted events after an id", func(t *testing.T) { setup() - lastEventGrn := "database/dash/1" + lastEventEntityId := "database/dash/1" err := service.SaveEvent(ctx, SaveEventCmd{ - Grn: "database/dash/3", + EntityId: "database/dash/3", EventType: EntityEventTypeCreate, }) require.NoError(t, err) @@ -82,12 +82,12 @@ func TestEntityEventsService(t *testing.T) { firstEvId := firstEv.Id err = service.SaveEvent(ctx, SaveEventCmd{ - Grn: "database/dash/2", + EntityId: "database/dash/2", EventType: EntityEventTypeCreate, }) require.NoError(t, err) err = service.SaveEvent(ctx, SaveEventCmd{ - Grn: lastEventGrn, + EntityId: lastEventEntityId, EventType: EntityEventTypeCreate, }) require.NoError(t, err) @@ -95,22 +95,22 @@ func TestEntityEventsService(t *testing.T) { evs, err := service.GetAllEventsAfter(ctx, firstEvId) require.NoError(t, err) require.Len(t, evs, 2) - require.Equal(t, evs[0].Grn, "database/dash/2") - require.Equal(t, evs[1].Grn, lastEventGrn) + require.Equal(t, evs[0].EntityId, "database/dash/2") + require.Equal(t, evs[1].EntityId, lastEventEntityId) }) t.Run("Should delete old events", func(t *testing.T) { setup() _ = service.SaveEvent(ctx, SaveEventCmd{ - Grn: "database/dash/3", + EntityId: "database/dash/3", EventType: EntityEventTypeCreate, }) _ = service.SaveEvent(ctx, SaveEventCmd{ - Grn: "database/dash/2", + EntityId: "database/dash/2", EventType: EntityEventTypeCreate, }) _ = service.SaveEvent(ctx, SaveEventCmd{ - Grn: "database/dash/1", + EntityId: "database/dash/1", EventType: EntityEventTypeCreate, }) @@ -136,3 +136,48 @@ func TestEntityEventsService(t *testing.T) { require.Len(t, evs, 0) }) } + +func TestCreateDatabaseEntityId(t *testing.T) { + tests := []struct { + name string + entityType EntityType + orgId int64 + internalId interface{} + expected string + }{ + { + name: "int64 internal id", + entityType: EntityTypeDashboard, + orgId: 10, + internalId: int64(45), + expected: "database/10/dashboard/45", + }, + { + name: "big-ish int64 internal id", + entityType: EntityTypeDashboard, + orgId: 10, + internalId: int64(12412421), + expected: "database/10/dashboard/12412421", + }, + { + name: "int internal id", + entityType: EntityTypeDashboard, + orgId: 10, + internalId: int(1244), + expected: "database/10/dashboard/1244", + }, + { + name: "string internal id", + entityType: EntityTypeDashboard, + orgId: 10, + internalId: "string-internal-id", + expected: "database/10/dashboard/string-internal-id", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, CreateDatabaseEntityId(tt.internalId, tt.orgId, tt.entityType)) + }) + } +}