diff --git a/database/sqlite3/subscription.go b/database/sqlite3/subscription.go index e727b517de..699153da45 100644 --- a/database/sqlite3/subscription.go +++ b/database/sqlite3/subscription.go @@ -5,6 +5,7 @@ import ( "database/sql" "errors" "fmt" + "gopkg.in/guregu/null.v4" "math" "time" @@ -33,23 +34,23 @@ const ( updateSubscription = ` UPDATE subscriptions SET - name=$3, - endpoint_id=$4, - source_id=$5, - alert_config_count=$6, - alert_config_threshold=$7, - retry_config_type=$8, - retry_config_duration=$9, - retry_config_retry_count=$10, - filter_config_event_types=$11, - filter_config_filter_headers=$12, - filter_config_filter_body=$13, - filter_config_filter_is_flattened=$14, - rate_limit_config_count=$15, - rate_limit_config_duration=$16, - function=$17, - updated_at=now() - WHERE id = $1 AND project_id = $2 + name=$1, + endpoint_id=$2, + source_id=$3, + alert_config_count=$4, + alert_config_threshold=$5, + retry_config_type=$6, + retry_config_duration=$7, + retry_config_retry_count=$8, + filter_config_event_types=$9, + filter_config_filter_headers=$10, + filter_config_filter_body=$11, + filter_config_filter_is_flattened=$12, + rate_limit_config_count=$13, + rate_limit_config_duration=$14, + function=$15, + updated_at=$16 + WHERE id = $17 AND project_id = $18 AND deleted_at IS NULL; ` @@ -252,8 +253,8 @@ const ( deleteSubscriptions = ` UPDATE subscriptions SET - deleted_at = NOW() - WHERE id = $1 AND project_id = $2; + deleted_at = $1 + WHERE id = $2 AND project_id = $3; ` ) @@ -320,13 +321,13 @@ func (s *subscriptionRepo) LoadAllSubscriptionConfig(ctx context.Context, projec func() { defer closeWithError(rows) for rows.Next() { - sub := datastore.Subscription{} + sub := dbSubscription{} if err = rows.StructScan(&sub); err != nil { return } nullifyEmptyConfig(&sub) - subs[counter] = sub + subs[counter] = *sub.toDatastoreSubscription() counter++ } @@ -411,13 +412,13 @@ func (s *subscriptionRepo) fetchChangedSubscriptionConfig(ctx context.Context, c func() { defer closeWithError(rows) for rows.Next() { - sub := datastore.Subscription{} + sub := dbSubscription{} if err = rows.StructScan(&sub); err != nil { return } nullifyEmptyConfig(&sub) - subs[counter] = sub + subs[counter] = *sub.toDatastoreSubscription() counter++ } @@ -490,7 +491,7 @@ func (s *subscriptionRepo) CreateSubscription(ctx context.Context, projectID str return ErrSubscriptionNotCreated } - _subscription := &datastore.Subscription{} + _subscription := &dbSubscription{} err = s.db.QueryRowxContext(ctx, fmt.Sprintf(fetchSubscriptionByID, "s.id", "s.project_id"), subscription.UID, projectID).StructScan(_subscription) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -500,7 +501,7 @@ func (s *subscriptionRepo) CreateSubscription(ctx context.Context, projectID str } nullifyEmptyConfig(_subscription) - *subscription = *_subscription + *subscription = *_subscription.toDatastoreSubscription() return nil } @@ -529,11 +530,10 @@ func (s *subscriptionRepo) UpdateSubscription(ctx context.Context, projectID str fc.Filter.IsFlattened = true // this is just a flag so we can identify old records result, err := s.db.ExecContext( - ctx, updateSubscription, subscription.UID, projectID, - subscription.Name, subscription.EndpointID, sourceID, - ac.Count, ac.Threshold, rc.Type, rc.Duration, rc.RetryCount, - fc.EventTypes, fc.Filter.Headers, fc.Filter.Body, fc.Filter.IsFlattened, - rlc.Count, rlc.Duration, subscription.Function, + ctx, updateSubscription, subscription.Name, subscription.EndpointID, sourceID, + ac.Count, ac.Threshold, rc.Type, rc.Duration, rc.RetryCount, fc.EventTypes, + fc.Filter.Headers, fc.Filter.Body, fc.Filter.IsFlattened, rlc.Count, + rlc.Duration, subscription.Function, time.Now(), subscription.UID, projectID, ) if err != nil { return err @@ -548,7 +548,7 @@ func (s *subscriptionRepo) UpdateSubscription(ctx context.Context, projectID str return ErrSubscriptionNotUpdated } - _subscription := &datastore.Subscription{} + _subscription := &dbSubscription{} err = s.db.QueryRowxContext(ctx, fmt.Sprintf(fetchSubscriptionByID, "s.id", "s.project_id"), subscription.UID, projectID).StructScan(_subscription) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -558,7 +558,7 @@ func (s *subscriptionRepo) UpdateSubscription(ctx context.Context, projectID str } nullifyEmptyConfig(_subscription) - *subscription = *_subscription + *subscription = *_subscription.toDatastoreSubscription() return nil } @@ -668,7 +668,7 @@ func (s *subscriptionRepo) LoadSubscriptionsPaged(ctx context.Context, projectID } func (s *subscriptionRepo) DeleteSubscription(ctx context.Context, projectID string, subscription *datastore.Subscription) error { - result, err := s.db.ExecContext(ctx, deleteSubscriptions, subscription.UID, projectID) + result, err := s.db.ExecContext(ctx, deleteSubscriptions, time.Now(), subscription.UID, projectID) if err != nil { return err } @@ -686,7 +686,7 @@ func (s *subscriptionRepo) DeleteSubscription(ctx context.Context, projectID str } func (s *subscriptionRepo) FindSubscriptionByID(ctx context.Context, projectID string, subscriptionID string) (*datastore.Subscription, error) { - subscription := &datastore.Subscription{} + subscription := &dbSubscription{} err := s.db.QueryRowxContext(ctx, fmt.Sprintf(fetchSubscriptionByID, "s.id", "s.project_id"), subscriptionID, projectID).StructScan(subscription) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -697,7 +697,7 @@ func (s *subscriptionRepo) FindSubscriptionByID(ctx context.Context, projectID s nullifyEmptyConfig(subscription) - return subscription, nil + return subscription.toDatastoreSubscription(), nil } func (s *subscriptionRepo) FindSubscriptionsBySourceID(ctx context.Context, projectID string, sourceID string) ([]datastore.Subscription, error) { @@ -727,7 +727,7 @@ func (s *subscriptionRepo) FindSubscriptionsByEndpointID(ctx context.Context, pr } func (s *subscriptionRepo) FindSubscriptionByDeviceID(ctx context.Context, projectId string, deviceID string, subscriptionType datastore.SubscriptionType) (*datastore.Subscription, error) { - subscription := &datastore.Subscription{} + subscription := &dbSubscription{} err := s.db.QueryRowxContext(ctx, fetchSubscriptionByDeviceID, deviceID, projectId, subscriptionType).StructScan(subscription) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -739,7 +739,7 @@ func (s *subscriptionRepo) FindSubscriptionByDeviceID(ctx context.Context, proje nullifyEmptyConfig(subscription) - return subscription, nil + return subscription.toDatastoreSubscription(), nil } func (s *subscriptionRepo) FindCLISubscriptions(ctx context.Context, projectID string) ([]datastore.Subscription, error) { @@ -810,7 +810,7 @@ var ( emptyRateLimitConfig = datastore.RateLimitConfiguration{} ) -func nullifyEmptyConfig(sub *datastore.Subscription) { +func nullifyEmptyConfig(sub *dbSubscription) { if sub.AlertConfig != nil && *sub.AlertConfig == emptyAlertConfig { sub.AlertConfig = nil } @@ -830,15 +830,59 @@ func scanSubscriptions(rows *sqlx.Rows) ([]datastore.Subscription, error) { defer closeWithError(rows) for rows.Next() { - sub := datastore.Subscription{} + sub := dbSubscription{} err = rows.StructScan(&sub) if err != nil { return nil, err } nullifyEmptyConfig(&sub) - subscriptions = append(subscriptions, sub) + subscriptions = append(subscriptions, *sub.toDatastoreSubscription()) } return subscriptions, nil } + +type dbSubscription struct { + UID string `db:"id"` + Name string `db:"name"` + Type datastore.SubscriptionType `db:"type"` + ProjectID string `db:"project_id"` + SourceID string `db:"source_id"` + EndpointID string `db:"endpoint_id"` + DeviceID string `db:"device_id"` + Function null.String `db:"function"` + Source *datastore.Source `db:"source_metadata"` + Endpoint *datastore.Endpoint `db:"endpoint_metadata"` + Device *datastore.Device `db:"device_metadata"` + AlertConfig *datastore.AlertConfiguration `db:"alert_config"` + RetryConfig *datastore.RetryConfiguration `db:"retry_config"` + FilterConfig *datastore.FilterConfiguration `db:"filter_config"` + RateLimitConfig *datastore.RateLimitConfiguration `db:"rate_limit_config"` + CreatedAt string `db:"created_at"` + UpdatedAt string `db:"updated_at"` + DeletedAt *string `db:"deleted_at"` +} + +func (ss *dbSubscription) toDatastoreSubscription() *datastore.Subscription { + return &datastore.Subscription{ + UID: ss.UID, + Name: ss.Name, + Type: ss.Type, + ProjectID: ss.ProjectID, + SourceID: ss.SourceID, + EndpointID: ss.EndpointID, + DeviceID: ss.DeviceID, + Function: ss.Function, + Source: ss.Source, + Endpoint: ss.Endpoint, + Device: ss.Device, + AlertConfig: ss.AlertConfig, + RetryConfig: ss.RetryConfig, + FilterConfig: ss.FilterConfig, + RateLimitConfig: ss.RateLimitConfig, + CreatedAt: asTime(ss.CreatedAt), + UpdatedAt: asTime(ss.UpdatedAt), + DeletedAt: asNullTime(ss.DeletedAt), + } +} diff --git a/database/sqlite3/subscription_test.go b/database/sqlite3/subscription_test.go index 356ab77b6c..8541b2b8aa 100644 --- a/database/sqlite3/subscription_test.go +++ b/database/sqlite3/subscription_test.go @@ -51,310 +51,260 @@ func seedSubscription(t *testing.T, db database.Database, project *datastore.Pro return s } -func Test_LoadSubscriptionsPaged(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() - - subRepo := NewSubscriptionRepo(db) - - source := seedSource(t, db) - project := seedProject(t, db) - endpoint := seedEndpoint(t, db) - device := seedDevice(t, db) - subMap := map[string]*datastore.Subscription{} - var newSub *datastore.Subscription - for i := 0; i < 100; i++ { - newSub = generateSubscription(project, source, endpoint, device) - require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) - subMap[newSub.UID] = newSub - } +func TestSubscription(t *testing.T) { + t.Run("LoadSubscriptionsPaged", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() + + subRepo := NewSubscriptionRepo(db) + + source := seedSource(t, db) + project := seedProject(t, db) + endpoint := seedEndpoint(t, db) + device := seedDevice(t, db) + subMap := map[string]*datastore.Subscription{} + var newSub *datastore.Subscription + for i := 0; i < 100; i++ { + newSub = generateSubscription(project, source, endpoint, device) + require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) + subMap[newSub.UID] = newSub + } - type Expected struct { - paginationData datastore.PaginationData - } + type Expected struct { + paginationData datastore.PaginationData + } - tests := []struct { - name string - EndpointIDs []string - SubscriptionName string - pageData datastore.Pageable - expected Expected - }{ - { - name: "Load Subscriptions Paged - 10 records", - pageData: datastore.Pageable{PerPage: 3, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, - expected: Expected{ - paginationData: datastore.PaginationData{ - PerPage: 3, + tests := []struct { + name string + EndpointIDs []string + SubscriptionName string + pageData datastore.Pageable + expected Expected + }{ + { + name: "Load Subscriptions Paged - 10 records", + pageData: datastore.Pageable{PerPage: 3, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, + expected: Expected{ + paginationData: datastore.PaginationData{ + PerPage: 3, + }, }, }, - }, - { - name: "Load Subscriptions Paged - 1 record - filter by name", - SubscriptionName: newSub.Name, - pageData: datastore.Pageable{PerPage: 1, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, - expected: Expected{ - paginationData: datastore.PaginationData{ - PerPage: 1, + { + name: "Load Subscriptions Paged - 1 record - filter by name", + SubscriptionName: newSub.Name, + pageData: datastore.Pageable{PerPage: 1, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, + expected: Expected{ + paginationData: datastore.PaginationData{ + PerPage: 1, + }, }, }, - }, - { - name: "Load Subscriptions Paged - 12 records", - pageData: datastore.Pageable{PerPage: 4, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, - expected: Expected{ - paginationData: datastore.PaginationData{ - PerPage: 4, + { + name: "Load Subscriptions Paged - 12 records", + pageData: datastore.Pageable{PerPage: 4, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, + expected: Expected{ + paginationData: datastore.PaginationData{ + PerPage: 4, + }, }, }, - }, - { - name: "Load Subscriptions Paged - 0 records", - pageData: datastore.Pageable{PerPage: 10, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, - expected: Expected{ - paginationData: datastore.PaginationData{ - PerPage: 10, + { + name: "Load Subscriptions Paged - 0 records", + pageData: datastore.Pageable{PerPage: 10, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, + expected: Expected{ + paginationData: datastore.PaginationData{ + PerPage: 10, + }, }, }, - }, - { - name: "Load Subscriptions Paged with Endpoint ID - 1 record", - EndpointIDs: []string{endpoint.UID}, - pageData: datastore.Pageable{PerPage: 3, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, - expected: Expected{ - paginationData: datastore.PaginationData{ - PerPage: 3, + { + name: "Load Subscriptions Paged with Endpoint ID - 1 record", + EndpointIDs: []string{endpoint.UID}, + pageData: datastore.Pageable{PerPage: 3, Direction: datastore.Next, NextCursor: fmt.Sprintf("%d", math.MaxInt)}, + expected: Expected{ + paginationData: datastore.PaginationData{ + PerPage: 3, + }, }, }, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - subs, pageable, err := subRepo.LoadSubscriptionsPaged(context.Background(), project.UID, &datastore.FilterBy{EndpointIDs: tc.EndpointIDs, SubscriptionName: tc.SubscriptionName}, tc.pageData) - require.NoError(t, err) - - require.Equal(t, tc.expected.paginationData.PerPage, pageable.PerPage) - - require.Equal(t, tc.expected.paginationData.PerPage, int64(len(subs))) - - for _, dbSub := range subs { - - require.NotEmpty(t, dbSub.CreatedAt) - require.NotEmpty(t, dbSub.UpdatedAt) - - dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} - - require.Equal(t, dbSub.Endpoint.UID, endpoint.UID) - require.Equal(t, dbSub.Endpoint.Name, endpoint.Name) - require.Equal(t, dbSub.Endpoint.ProjectID, endpoint.ProjectID) - require.Equal(t, dbSub.Endpoint.SupportEmail, endpoint.SupportEmail) - - require.Equal(t, dbSub.Source.UID, source.UID) - require.Equal(t, dbSub.Source.Name, source.Name) - require.Equal(t, dbSub.Source.Type, source.Type) - require.Equal(t, dbSub.Source.MaskID, source.MaskID) - require.Equal(t, dbSub.Source.ProjectID, source.ProjectID) - require.Equal(t, dbSub.Source.IsDisabled, source.IsDisabled) - - dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil + } - require.Equal(t, dbSub.UID, subMap[dbSub.UID].UID) - } - }) - } -} + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + subs, pageable, err := subRepo.LoadSubscriptionsPaged(context.Background(), project.UID, &datastore.FilterBy{EndpointIDs: tc.EndpointIDs, SubscriptionName: tc.SubscriptionName}, tc.pageData) + require.NoError(t, err) -func Test_DeleteSubscription(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + require.Equal(t, tc.expected.paginationData.PerPage, pageable.PerPage) - subRepo := NewSubscriptionRepo(db) + require.Equal(t, tc.expected.paginationData.PerPage, int64(len(subs))) - project := seedProject(t, db) - source := seedSource(t, db) - endpoint := seedEndpoint(t, db) + for _, dbSub := range subs { - newSub := generateSubscription(project, source, endpoint, &datastore.Device{}) + require.NotEmpty(t, dbSub.CreatedAt) + require.NotEmpty(t, dbSub.UpdatedAt) - err := subRepo.CreateSubscription(context.Background(), project.UID, newSub) - require.NoError(t, err) + dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} - // delete the sub - err = subRepo.DeleteSubscription(context.Background(), project.UID, newSub) - require.NoError(t, err) + require.Equal(t, dbSub.Endpoint.UID, endpoint.UID) + require.Equal(t, dbSub.Endpoint.Name, endpoint.Name) + require.Equal(t, dbSub.Endpoint.ProjectID, endpoint.ProjectID) + require.Equal(t, dbSub.Endpoint.SupportEmail, endpoint.SupportEmail) - // Fetch sub again - _, err = subRepo.FindSubscriptionByID(context.Background(), project.UID, newSub.UID) - require.Equal(t, err, datastore.ErrSubscriptionNotFound) -} + require.Equal(t, dbSub.Source.UID, source.UID) + require.Equal(t, dbSub.Source.Name, source.Name) + require.Equal(t, dbSub.Source.Type, source.Type) + require.Equal(t, dbSub.Source.MaskID, source.MaskID) + require.Equal(t, dbSub.Source.ProjectID, source.ProjectID) + require.Equal(t, dbSub.Source.IsDisabled, source.IsDisabled) -func Test_CreateSubscription(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil - subRepo := NewSubscriptionRepo(db) + require.Equal(t, dbSub.UID, subMap[dbSub.UID].UID) + } + }) + } + }) - project := seedProject(t, db) - source := seedSource(t, db) - endpoint := seedEndpoint(t, db) + t.Run("DeleteSubscription", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() - newSub := generateSubscription(project, source, endpoint, &datastore.Device{}) - require.NoError(t, subRepo.CreateSubscription(context.Background(), newSub.ProjectID, newSub)) + subRepo := NewSubscriptionRepo(db) - dbSub, err := subRepo.FindSubscriptionByID(context.Background(), newSub.ProjectID, newSub.UID) - require.NoError(t, err) + project := seedProject(t, db) + source := seedSource(t, db) + endpoint := seedEndpoint(t, db) - require.NotEmpty(t, dbSub.CreatedAt) - require.NotEmpty(t, dbSub.UpdatedAt) + newSub := generateSubscription(project, source, endpoint, &datastore.Device{}) - dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} - dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil + err := subRepo.CreateSubscription(context.Background(), project.UID, newSub) + require.NoError(t, err) - require.Equal(t, dbSub.UID, newSub.UID) -} + // delete the sub + err = subRepo.DeleteSubscription(context.Background(), project.UID, newSub) + require.NoError(t, err) -func Test_CountEndpointSubscriptions(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + // Fetch sub again + _, err = subRepo.FindSubscriptionByID(context.Background(), project.UID, newSub.UID) + require.Equal(t, err, datastore.ErrSubscriptionNotFound) + }) - subRepo := NewSubscriptionRepo(db) + t.Run("CreateSubscription", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() - project := seedProject(t, db) - source := seedSource(t, db) - endpoint := seedEndpoint(t, db) + subRepo := NewSubscriptionRepo(db) - newSub1 := generateSubscription(project, source, endpoint, &datastore.Device{}) - require.NoError(t, subRepo.CreateSubscription(context.Background(), newSub1.ProjectID, newSub1)) + project := seedProject(t, db) + source := seedSource(t, db) + endpoint := seedEndpoint(t, db) - newSub2 := generateSubscription(project, source, endpoint, &datastore.Device{}) - require.NoError(t, subRepo.CreateSubscription(context.Background(), newSub2.ProjectID, newSub2)) + newSub := generateSubscription(project, source, endpoint, &datastore.Device{}) + require.NoError(t, subRepo.CreateSubscription(context.Background(), newSub.ProjectID, newSub)) - count, err := subRepo.CountEndpointSubscriptions(context.Background(), newSub1.ProjectID, endpoint.UID) - require.NoError(t, err) + dbSub, err := subRepo.FindSubscriptionByID(context.Background(), newSub.ProjectID, newSub.UID) + require.NoError(t, err) - require.Equal(t, int64(2), count) -} + require.NotEmpty(t, dbSub.CreatedAt) + require.NotEmpty(t, dbSub.UpdatedAt) -func Test_UpdateSubscription(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} + dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil - subRepo := NewSubscriptionRepo(db) + require.Equal(t, dbSub.UID, newSub.UID) + }) - project := seedProject(t, db) - source := seedSource(t, db) - endpoint := seedEndpoint(t, db) + t.Run("CountEndpointSubscriptions", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() - newSub := generateSubscription(project, source, endpoint, &datastore.Device{}) - require.NoError(t, subRepo.CreateSubscription(context.Background(), newSub.ProjectID, newSub)) - - update := &datastore.Subscription{ - UID: newSub.UID, - Name: "tyne&wear", - ProjectID: newSub.ProjectID, - Type: newSub.Type, - SourceID: seedSource(t, db).UID, - EndpointID: seedEndpoint(t, db).UID, - AlertConfig: &datastore.DefaultAlertConfig, - RetryConfig: &datastore.DefaultRetryConfig, - FilterConfig: newSub.FilterConfig, - RateLimitConfig: &datastore.DefaultRateLimitConfig, - } + subRepo := NewSubscriptionRepo(db) - err := subRepo.UpdateSubscription(context.Background(), project.UID, update) - require.NoError(t, err) + project := seedProject(t, db) + source := seedSource(t, db) + endpoint := seedEndpoint(t, db) - dbSub, err := subRepo.FindSubscriptionByID(context.Background(), newSub.ProjectID, newSub.UID) - require.NoError(t, err) + newSub1 := generateSubscription(project, source, endpoint, &datastore.Device{}) + require.NoError(t, subRepo.CreateSubscription(context.Background(), newSub1.ProjectID, newSub1)) - require.NotEmpty(t, dbSub.CreatedAt) - require.NotEmpty(t, dbSub.UpdatedAt) + newSub2 := generateSubscription(project, source, endpoint, &datastore.Device{}) + require.NoError(t, subRepo.CreateSubscription(context.Background(), newSub2.ProjectID, newSub2)) - dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} - dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil + count, err := subRepo.CountEndpointSubscriptions(context.Background(), newSub1.ProjectID, endpoint.UID) + require.NoError(t, err) - require.Equal(t, dbSub.UID, update.UID) - require.Equal(t, dbSub.Name, update.Name) -} + require.Equal(t, int64(2), count) + }) -func Test_FindSubscriptionByID(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + t.Run("UpdateSubscription", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() - subRepo := NewSubscriptionRepo(db) + subRepo := NewSubscriptionRepo(db) - project := seedProject(t, db) - source := seedSource(t, db) - endpoint := seedEndpoint(t, db) + project := seedProject(t, db) + source := seedSource(t, db) + endpoint := seedEndpoint(t, db) - newSub := generateSubscription(project, source, endpoint, &datastore.Device{}) + newSub := generateSubscription(project, source, endpoint, &datastore.Device{}) + require.NoError(t, subRepo.CreateSubscription(context.Background(), newSub.ProjectID, newSub)) - // Fetch sub again - _, err := subRepo.FindSubscriptionByID(context.Background(), project.UID, newSub.UID) - require.Error(t, err) - require.EqualError(t, err, datastore.ErrSubscriptionNotFound.Error()) + update := &datastore.Subscription{ + UID: newSub.UID, + Name: "tyne&wear", + ProjectID: newSub.ProjectID, + Type: newSub.Type, + SourceID: seedSource(t, db).UID, + EndpointID: seedEndpoint(t, db).UID, + AlertConfig: &datastore.DefaultAlertConfig, + RetryConfig: &datastore.DefaultRetryConfig, + FilterConfig: newSub.FilterConfig, + RateLimitConfig: &datastore.DefaultRateLimitConfig, + } - require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) + err := subRepo.UpdateSubscription(context.Background(), project.UID, update) + require.NoError(t, err) - // Fetch sub again - dbSub, err := subRepo.FindSubscriptionByID(context.Background(), project.UID, newSub.UID) - require.NoError(t, err) + dbSub, err := subRepo.FindSubscriptionByID(context.Background(), newSub.ProjectID, newSub.UID) + require.NoError(t, err) - require.NotEmpty(t, dbSub.CreatedAt) - require.NotEmpty(t, dbSub.UpdatedAt) + require.NotEmpty(t, dbSub.CreatedAt) + require.NotEmpty(t, dbSub.UpdatedAt) - dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} - require.Equal(t, dbSub.Endpoint.UID, endpoint.UID) - require.Equal(t, dbSub.Endpoint.Name, endpoint.Name) - require.Equal(t, dbSub.Endpoint.ProjectID, endpoint.ProjectID) - require.Equal(t, dbSub.Endpoint.SupportEmail, endpoint.SupportEmail) + dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} + dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil - require.Equal(t, dbSub.Source.UID, source.UID) - require.Equal(t, dbSub.Source.Name, source.Name) - require.Equal(t, dbSub.Source.Type, source.Type) - require.Equal(t, dbSub.Source.MaskID, source.MaskID) - require.Equal(t, dbSub.Source.ProjectID, source.ProjectID) - require.Equal(t, dbSub.Source.IsDisabled, source.IsDisabled) + require.Equal(t, dbSub.UID, update.UID) + require.Equal(t, dbSub.Name, update.Name) + }) - dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil + t.Run("FindSubscriptionByID", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() - require.Equal(t, dbSub.UID, newSub.UID) -} + subRepo := NewSubscriptionRepo(db) -func Test_FindSubscriptionsBySourceID(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + project := seedProject(t, db) + source := seedSource(t, db) + endpoint := seedEndpoint(t, db) - subRepo := NewSubscriptionRepo(db) + newSub := generateSubscription(project, source, endpoint, &datastore.Device{}) - source := seedSource(t, db) - project := seedProject(t, db) - endpoint := seedEndpoint(t, db) - - subMap := map[string]*datastore.Subscription{} - for i := 0; i < 5; i++ { - var newSub *datastore.Subscription - if i == 3 { - newSub = generateSubscription(project, seedSource(t, db), endpoint, &datastore.Device{}) - } else { - newSub = generateSubscription(project, source, endpoint, &datastore.Device{}) - } + // Fetch sub again + _, err := subRepo.FindSubscriptionByID(context.Background(), project.UID, newSub.UID) + require.Error(t, err) + require.EqualError(t, err, datastore.ErrSubscriptionNotFound.Error()) require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) - subMap[newSub.UID] = newSub - } - // Fetch sub again - dbSubs, err := subRepo.FindSubscriptionsBySourceID(context.Background(), project.UID, source.UID) - require.NoError(t, err) - require.Equal(t, 4, len(dbSubs)) - - for _, dbSub := range dbSubs { + // Fetch sub again + dbSub, err := subRepo.FindSubscriptionByID(context.Background(), project.UID, newSub.UID) + require.NoError(t, err) require.NotEmpty(t, dbSub.CreatedAt) require.NotEmpty(t, dbSub.UpdatedAt) @@ -374,138 +324,190 @@ func Test_FindSubscriptionsBySourceID(t *testing.T) { dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil - require.Equal(t, dbSub.UID, subMap[dbSub.UID].UID) - } -} + require.Equal(t, dbSub.UID, newSub.UID) + }) -func Test_FindSubscriptionByEndpointID(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + t.Run("FindSubscriptionsBySourceID", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() - subRepo := NewSubscriptionRepo(db) + subRepo := NewSubscriptionRepo(db) - source := seedSource(t, db) - project := seedProject(t, db) - endpoint := seedEndpoint(t, db) + source := seedSource(t, db) + project := seedProject(t, db) + endpoint := seedEndpoint(t, db) - subMap := map[string]*datastore.Subscription{} - for i := 0; i < 8; i++ { - var newSub *datastore.Subscription - if i == 3 { - newSub = generateSubscription(project, source, seedEndpoint(t, db), &datastore.Device{}) - } else { - newSub = generateSubscription(project, source, endpoint, &datastore.Device{}) + subMap := map[string]*datastore.Subscription{} + for i := 0; i < 5; i++ { + var newSub *datastore.Subscription + if i == 3 { + newSub = generateSubscription(project, seedSource(t, db), endpoint, &datastore.Device{}) + } else { + newSub = generateSubscription(project, source, endpoint, &datastore.Device{}) + } + + require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) + subMap[newSub.UID] = newSub } - require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) - subMap[newSub.UID] = newSub - } + // Fetch sub again + dbSubs, err := subRepo.FindSubscriptionsBySourceID(context.Background(), project.UID, source.UID) + require.NoError(t, err) + require.Equal(t, 4, len(dbSubs)) - // Fetch sub again - dbSubs, err := subRepo.FindSubscriptionsByEndpointID(context.Background(), project.UID, endpoint.UID) - require.NoError(t, err) - require.Equal(t, 7, len(dbSubs)) + for _, dbSub := range dbSubs { - for _, dbSub := range dbSubs { + require.NotEmpty(t, dbSub.CreatedAt) + require.NotEmpty(t, dbSub.UpdatedAt) - require.NotEmpty(t, dbSub.CreatedAt) - require.NotEmpty(t, dbSub.UpdatedAt) + dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} + require.Equal(t, dbSub.Endpoint.UID, endpoint.UID) + require.Equal(t, dbSub.Endpoint.Name, endpoint.Name) + require.Equal(t, dbSub.Endpoint.ProjectID, endpoint.ProjectID) + require.Equal(t, dbSub.Endpoint.SupportEmail, endpoint.SupportEmail) - dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} - require.Equal(t, dbSub.Endpoint.UID, endpoint.UID) - require.Equal(t, dbSub.Endpoint.Name, endpoint.Name) - require.Equal(t, dbSub.Endpoint.ProjectID, endpoint.ProjectID) - require.Equal(t, dbSub.Endpoint.SupportEmail, endpoint.SupportEmail) + require.Equal(t, dbSub.Source.UID, source.UID) + require.Equal(t, dbSub.Source.Name, source.Name) + require.Equal(t, dbSub.Source.Type, source.Type) + require.Equal(t, dbSub.Source.MaskID, source.MaskID) + require.Equal(t, dbSub.Source.ProjectID, source.ProjectID) + require.Equal(t, dbSub.Source.IsDisabled, source.IsDisabled) - require.Equal(t, dbSub.Source.UID, source.UID) - require.Equal(t, dbSub.Source.Name, source.Name) - require.Equal(t, dbSub.Source.Type, source.Type) - require.Equal(t, dbSub.Source.MaskID, source.MaskID) - require.Equal(t, dbSub.Source.ProjectID, source.ProjectID) - require.Equal(t, dbSub.Source.IsDisabled, source.IsDisabled) + dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil - dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil + require.Equal(t, dbSub.UID, subMap[dbSub.UID].UID) + } + }) - require.Equal(t, dbSub.UID, subMap[dbSub.UID].UID) - } -} + t.Run("FindSubscriptionByEndpointID", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() -func Test_FindSubscriptionByDeviceID(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + subRepo := NewSubscriptionRepo(db) - subRepo := NewSubscriptionRepo(db) + source := seedSource(t, db) + project := seedProject(t, db) + endpoint := seedEndpoint(t, db) - project := seedProject(t, db) - source := seedSource(t, db) - endpoint := seedEndpoint(t, db) - device := seedDevice(t, db) - newSub := generateSubscription(project, source, endpoint, device) + subMap := map[string]*datastore.Subscription{} + for i := 0; i < 8; i++ { + var newSub *datastore.Subscription + if i == 3 { + newSub = generateSubscription(project, source, seedEndpoint(t, db), &datastore.Device{}) + } else { + newSub = generateSubscription(project, source, endpoint, &datastore.Device{}) + } - require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) + require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) + subMap[newSub.UID] = newSub + } - // Fetch sub again - dbSub, err := subRepo.FindSubscriptionByDeviceID(context.Background(), project.UID, device.UID, newSub.Type) - require.NoError(t, err) + // Fetch sub again + dbSubs, err := subRepo.FindSubscriptionsByEndpointID(context.Background(), project.UID, endpoint.UID) + require.NoError(t, err) + require.Equal(t, 7, len(dbSubs)) - require.NotEmpty(t, dbSub.CreatedAt) - require.NotEmpty(t, dbSub.UpdatedAt) + for _, dbSub := range dbSubs { - dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} - require.Nil(t, dbSub.Endpoint) - require.Nil(t, dbSub.Source) + require.NotEmpty(t, dbSub.CreatedAt) + require.NotEmpty(t, dbSub.UpdatedAt) - require.Equal(t, device.UID, dbSub.Device.UID) - require.Equal(t, device.HostName, dbSub.Device.HostName) + dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} + require.Equal(t, dbSub.Endpoint.UID, endpoint.UID) + require.Equal(t, dbSub.Endpoint.Name, endpoint.Name) + require.Equal(t, dbSub.Endpoint.ProjectID, endpoint.ProjectID) + require.Equal(t, dbSub.Endpoint.SupportEmail, endpoint.SupportEmail) - dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil + require.Equal(t, dbSub.Source.UID, source.UID) + require.Equal(t, dbSub.Source.Name, source.Name) + require.Equal(t, dbSub.Source.Type, source.Type) + require.Equal(t, dbSub.Source.MaskID, source.MaskID) + require.Equal(t, dbSub.Source.ProjectID, source.ProjectID) + require.Equal(t, dbSub.Source.IsDisabled, source.IsDisabled) - require.Equal(t, dbSub.UID, newSub.UID) -} + dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil -func Test_FindCLISubscriptions(t *testing.T) { - db, closeFn := getDB(t) - defer closeFn() + require.Equal(t, dbSub.UID, subMap[dbSub.UID].UID) + } + }) - subRepo := NewSubscriptionRepo(db) + t.Run("FindSubscriptionByDeviceID", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() - source := seedSource(t, db) - project := seedProject(t, db) - endpoint := seedEndpoint(t, db) + subRepo := NewSubscriptionRepo(db) - for i := 0; i < 8; i++ { - newSub := &datastore.Subscription{ - UID: ulid.Make().String(), - Name: "Subscription", - Type: datastore.SubscriptionTypeCLI, - ProjectID: project.UID, - SourceID: source.UID, - EndpointID: endpoint.UID, - AlertConfig: &datastore.AlertConfiguration{ - Count: 10, - Threshold: "1m", - }, - RetryConfig: &datastore.RetryConfiguration{ - Type: "linear", - Duration: 3, - RetryCount: 10, - }, - FilterConfig: &datastore.FilterConfiguration{ - EventTypes: []string{"some.event"}, - Filter: datastore.FilterSchema{ - Headers: datastore.M{}, - Body: datastore.M{}, - }, - }, - } + project := seedProject(t, db) + source := seedSource(t, db) + endpoint := seedEndpoint(t, db) + device := seedDevice(t, db) + newSub := generateSubscription(project, source, endpoint, device) require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) - } - // Fetch sub again - dbSubs, err := subRepo.FindCLISubscriptions(context.Background(), project.UID) - require.NoError(t, err) - require.Equal(t, 8, len(dbSubs)) + // Fetch sub again + dbSub, err := subRepo.FindSubscriptionByDeviceID(context.Background(), project.UID, device.UID, newSub.Type) + require.NoError(t, err) + + require.NotEmpty(t, dbSub.CreatedAt) + require.NotEmpty(t, dbSub.UpdatedAt) + + dbSub.CreatedAt, dbSub.UpdatedAt = time.Time{}, time.Time{} + require.Nil(t, dbSub.Endpoint) + require.Nil(t, dbSub.Source) + + require.Equal(t, device.UID, dbSub.Device.UID) + require.Equal(t, device.HostName, dbSub.Device.HostName) + + dbSub.Source, dbSub.Endpoint, dbSub.Device = nil, nil, nil + + require.Equal(t, dbSub.UID, newSub.UID) + }) + + t.Run("FindCLISubscriptions", func(t *testing.T) { + db, closeFn := getDB(t) + defer closeFn() + + subRepo := NewSubscriptionRepo(db) + + source := seedSource(t, db) + project := seedProject(t, db) + endpoint := seedEndpoint(t, db) + + for i := 0; i < 8; i++ { + newSub := &datastore.Subscription{ + UID: ulid.Make().String(), + Name: "Subscription", + Type: datastore.SubscriptionTypeCLI, + ProjectID: project.UID, + SourceID: source.UID, + EndpointID: endpoint.UID, + AlertConfig: &datastore.AlertConfiguration{ + Count: 10, + Threshold: "1m", + }, + RetryConfig: &datastore.RetryConfiguration{ + Type: "linear", + Duration: 3, + RetryCount: 10, + }, + FilterConfig: &datastore.FilterConfiguration{ + EventTypes: []string{"some.event"}, + Filter: datastore.FilterSchema{ + Headers: datastore.M{}, + Body: datastore.M{}, + }, + }, + } + + require.NoError(t, subRepo.CreateSubscription(context.Background(), project.UID, newSub)) + } + + // Fetch sub again + dbSubs, err := subRepo.FindCLISubscriptions(context.Background(), project.UID) + require.NoError(t, err) + require.Equal(t, 8, len(dbSubs)) + }) } func seedDevice(t *testing.T, db database.Database) *datastore.Device { @@ -513,8 +515,9 @@ func seedDevice(t *testing.T, db database.Database) *datastore.Device { endpoint := seedEndpoint(t, db) d := &datastore.Device{ - UID: ulid.Make().String(), - ProjectID: project.UID, + UID: ulid.Make().String(), + ProjectID: project.UID, + EndpointID: endpoint.UID, HostName: "host1", Status: datastore.DeviceStatusOnline, diff --git a/sql/sqlite3/1731413863.sql b/sql/sqlite3/1731413863.sql index 19ccdd9005..f3280b21a3 100644 --- a/sql/sqlite3/1731413863.sql +++ b/sql/sqlite3/1731413863.sql @@ -26,7 +26,7 @@ create table if not exists configurations cb_success_threshold INTEGER default 1 not null, cb_observability_window INTEGER default 30 not null, cb_consecutive_failure_threshold INTEGER default 10 not null -); +) strict; -- event endpoints create table if not exists events_endpoints @@ -35,7 +35,7 @@ create table if not exists events_endpoints endpoint_id TEXT not null, FOREIGN KEY(endpoint_id) REFERENCES endpoints(id), FOREIGN KEY(event_id) REFERENCES events(id) -); +) strict; create index if not exists events_endpoints_temp_endpoint_id_idx on events_endpoints (endpoint_id); @@ -54,7 +54,7 @@ create table if not exists gorp_migrations ( id TEXT not null primary key, applied_at TEXT -); +) strict; -- project configurations create table if not exists project_configurations @@ -82,7 +82,7 @@ create table if not exists project_configurations created_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), deleted_at TEXT -); +) strict; -- source verifiers create table if not exists source_verifiers @@ -101,7 +101,7 @@ create table if not exists source_verifiers created_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), deleted_at TEXT -); +) strict; -- token bucket create table if not exists token_bucket @@ -112,7 +112,7 @@ create table if not exists token_bucket created_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), expires_at TEXT not null -); +) strict; -- users create table if not exists users @@ -131,7 +131,7 @@ create table if not exists users created_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), deleted_at TEXT -); +) strict; CREATE UNIQUE INDEX if not exists idx_unique_email_deleted_at ON users(email) @@ -149,7 +149,7 @@ create table if not exists organisations updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), deleted_at TEXT, FOREIGN KEY(owner_id) REFERENCES users(id) -); +) strict; create unique index if not exists idx_organisations_custom_domain_deleted_at on organisations (custom_domain, assigned_domain) @@ -171,7 +171,7 @@ create table if not exists projects constraint name_org_id_key unique (name, organisation_id, deleted_at), FOREIGN KEY(organisation_id) REFERENCES organisations(id), FOREIGN KEY(project_configuration_id) REFERENCES project_configurations(id) -); +) strict; create unique index if not exists idx_name_organisation_id_deleted_at on projects (organisation_id, name) @@ -189,7 +189,7 @@ create table if not exists applications updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), deleted_at TEXT, FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; -- devices todo(raymond): deprecate me create table if not exists devices @@ -203,7 +203,7 @@ create table if not exists devices last_seen_at TEXT not null, deleted_at TEXT, FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; -- endpoints create table if not exists endpoints @@ -230,7 +230,7 @@ create table if not exists endpoints name TEXT not null, url TEXT not null, FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; CREATE UNIQUE INDEX if not exists idx_name_project_id_deleted_at ON endpoints(name, project_id) @@ -268,7 +268,7 @@ create table if not exists api_keys FOREIGN KEY(role_project) REFERENCES projects(id), FOREIGN KEY(role_endpoint) REFERENCES endpoints(id), FOREIGN KEY(user_id) REFERENCES users(id) -); +) strict; CREATE UNIQUE INDEX if not exists idx_mask_id_deleted_at ON api_keys(mask_id) @@ -289,7 +289,7 @@ create table if not exists event_types updated_at TEXT default (strftime('%Y-%m-%dT%H:%M:%fZ')) not null, deprecated_at TEXT, FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; CREATE UNIQUE INDEX if not exists idx_name_project_id_deleted_at ON event_types(name, project_id) @@ -332,7 +332,7 @@ create table if not exists jobs updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), deleted_at TEXT, FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; -- meta events create table if not exists meta_events @@ -347,7 +347,7 @@ create table if not exists meta_events updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), deleted_at TEXT, FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; -- organisation invites create table if not exists organisation_invites @@ -367,7 +367,7 @@ create table if not exists organisation_invites FOREIGN KEY(role_project) REFERENCES projects(id), FOREIGN KEY(organisation_id) REFERENCES organisations(id), FOREIGN KEY(role_endpoint) REFERENCES endpoints(id) -); +) strict; CREATE UNIQUE INDEX if not exists idx_token_organisation_id_deleted_at ON organisation_invites(token, organisation_id) @@ -395,7 +395,7 @@ create table if not exists organisation_members FOREIGN KEY(role_endpoint) REFERENCES endpoints(id), FOREIGN KEY(organisation_id) REFERENCES organisations(id), FOREIGN KEY(user_id) REFERENCES users(id) -); +) strict; CREATE UNIQUE INDEX if not exists idx_organisation_id_user_id_deleted_at ON organisation_members(organisation_id, user_id) @@ -423,7 +423,7 @@ create table if not exists portal_links owner_id TEXT, can_manage_endpoint BOOLEAN default false, FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; CREATE UNIQUE INDEX if not exists idx_token_deleted_at ON portal_links(token) @@ -444,7 +444,7 @@ create table if not exists portal_links_endpoints endpoint_id TEXT not null, FOREIGN KEY(portal_link_id) REFERENCES portal_links(id), FOREIGN KEY(endpoint_id) REFERENCES endpoints(id) -); +) strict; create index if not exists idx_portal_links_endpoints_enpdoint_id on portal_links_endpoints (endpoint_id); @@ -476,7 +476,7 @@ create table if not exists sources updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), FOREIGN KEY(project_id) REFERENCES projects(id), FOREIGN KEY(source_verifier_id) REFERENCES source_verifiers(id) -); +) strict; CREATE UNIQUE INDEX if not exists idx_mask_id_project_id_deleted_at ON sources(mask_id, project_id) @@ -513,7 +513,7 @@ create table if not exists events updated_at TEXT not null default (strftime('%Y-%m-%dT%H:%M:%fZ')), FOREIGN KEY(source_id) REFERENCES sources(id), FOREIGN KEY(project_id) REFERENCES projects(name) -); +) strict; create index if not exists idx_events_created_at_key on events (created_at); @@ -572,7 +572,7 @@ create table if not exists subscriptions FOREIGN KEY(device_id) REFERENCES devices(id), FOREIGN KEY(endpoint_id) REFERENCES endpoints(id), FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; CREATE UNIQUE INDEX if not exists idx_name_project_id_deleted_at ON subscriptions(name, project_id) @@ -625,7 +625,7 @@ create table if not exists event_deliveries FOREIGN KEY(event_id) REFERENCES events(id), FOREIGN KEY(endpoint_id) REFERENCES endpoints(id), FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; -- delivery attempts create table if not exists delivery_attempts @@ -650,7 +650,7 @@ create table if not exists delivery_attempts FOREIGN KEY(event_delivery_id) REFERENCES event_deliveries(id), FOREIGN KEY(endpoint_id) REFERENCES endpoints(id), FOREIGN KEY(project_id) REFERENCES projects(id) -); +) strict; create index if not exists idx_delivery_attempts_created_at on delivery_attempts (created_at);