Merge pull request #275 from fastenhealth/nickmurray/add-postgres-db-option
This commit is contained in:
commit
8861e4b6ba
|
@ -30,6 +30,7 @@ func (c *configuration) Init() error {
|
|||
c.SetDefault("web.allow_unsafe_endpoints", false)
|
||||
|
||||
c.SetDefault("web.src.frontend.path", "/opt/fasten/web")
|
||||
c.SetDefault("database.type", "sqlite")
|
||||
c.SetDefault("database.location", "/opt/fasten/db/fasten.db")
|
||||
c.SetDefault("cache.location", "/opt/fasten/cache/")
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ type BackgroundJobStatus string
|
|||
type BackgroundJobType string
|
||||
type BackgroundJobSchedule string
|
||||
|
||||
type DatabaseRepositoryType string
|
||||
|
||||
const (
|
||||
ResourceListPageSize int = 20
|
||||
|
||||
|
@ -36,4 +38,7 @@ const (
|
|||
BackgroundJobScheduleWeekly BackgroundJobSchedule = "WEEKLY"
|
||||
BackgroundJobScheduleBiWeekly BackgroundJobSchedule = "BIWEEKLY"
|
||||
BackgroundJobScheduleMonthly BackgroundJobSchedule = "MONTHLY"
|
||||
|
||||
DatabaseRepositoryTypeSqlite DatabaseRepositoryType = "sqlite"
|
||||
DatabaseRepositoryTypePostgres DatabaseRepositoryType = "postgres"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/config"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/errors"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/event_bus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func NewRepository(appConfig config.Interface, globalLogger logrus.FieldLogger, eventBus event_bus.Interface) (DatabaseRepository, error) {
|
||||
switch pkg.DatabaseRepositoryType(appConfig.GetString("database.type")) {
|
||||
case pkg.DatabaseRepositoryTypeSqlite:
|
||||
return newSqliteRepository(appConfig, globalLogger, eventBus)
|
||||
case pkg.DatabaseRepositoryTypePostgres:
|
||||
return newPostgresRepository(appConfig, globalLogger, eventBus)
|
||||
default:
|
||||
return nil, errors.DatabaseTypeNotSupportedError(appConfig.GetString("database.type"))
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -3,14 +3,15 @@ package database
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/dominikbraun/graph"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/utils"
|
||||
databaseModel "github.com/fastenhealth/fasten-onprem/backend/pkg/models/database"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/utils"
|
||||
"golang.org/x/exp/slices"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type VertexResourcePlaceholder struct {
|
||||
|
@ -28,8 +29,8 @@ func (rp *VertexResourcePlaceholder) ID() string {
|
|||
// Retrieve a list of all fhir resources (vertex), and a list of all associations (edge)
|
||||
// Generate a graph
|
||||
// return list of root nodes, and their flattened related resources.
|
||||
func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graphType pkg.ResourceGraphType, options models.ResourceGraphOptions) (map[string][]*models.ResourceBase, *models.ResourceGraphMetadata, error) {
|
||||
currentUser, currentUserErr := sr.GetCurrentUser(ctx)
|
||||
func (gr *GormRepository) GetFlattenedResourceGraph(ctx context.Context, graphType pkg.ResourceGraphType, options models.ResourceGraphOptions) (map[string][]*models.ResourceBase, *models.ResourceGraphMetadata, error) {
|
||||
currentUser, currentUserErr := gr.GetCurrentUser(ctx)
|
||||
if currentUserErr != nil {
|
||||
return nil, nil, currentUserErr
|
||||
}
|
||||
|
@ -45,7 +46,7 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
var relatedResourceRelationships []models.RelatedResource
|
||||
|
||||
// SELECT * FROM related_resources WHERE user_id = "53c1e930-63af-46c9-b760-8e83cbc1abd9";
|
||||
result := sr.GormClient.WithContext(ctx).
|
||||
result := gr.GormClient.WithContext(ctx).
|
||||
Where(models.RelatedResource{
|
||||
ResourceBaseUserID: currentUser.ID,
|
||||
}).
|
||||
|
@ -59,7 +60,7 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
g := graph.New(resourceVertexId, graph.Directed(), graph.Acyclic(), graph.Rooted())
|
||||
|
||||
//// Get list of all resources TODO - REPLACED THIS
|
||||
//wrappedResourceModels, err := sr.ListResources(ctx, models.ListResourceQueryOptions{})
|
||||
//wrappedResourceModels, err := gr.ListResources(ctx, models.ListResourceQueryOptions{})
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
|
@ -109,7 +110,7 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
}
|
||||
|
||||
//add recriprocial relationships (depending on the graph type)
|
||||
relatedResourceRelationships = sr.PopulateGraphTypeReciprocalRelationships(graphType, relatedResourceRelationships)
|
||||
relatedResourceRelationships = gr.PopulateGraphTypeReciprocalRelationships(graphType, relatedResourceRelationships)
|
||||
|
||||
//add edges to graph
|
||||
for _, relationship := range relatedResourceRelationships {
|
||||
|
@ -121,7 +122,7 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
|
||||
if err != nil {
|
||||
//this may occur because vertices may not exist
|
||||
sr.Logger.Warnf("ignoring, an error occurred while adding edge: %v", err)
|
||||
gr.Logger.Warnf("ignoring, an error occurred while adding edge: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,7 +201,7 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
// Step 2: now that we've created a relationship graph using placeholders, we need to determine which page of resources to return
|
||||
// and look up the actual resources from the database.
|
||||
|
||||
resourceListDictionary, totalElements, err := sr.InflateResourceGraphAtPage(resourcePlaceholderListDictionary, options.Page)
|
||||
resourceListDictionary, totalElements, err := gr.InflateResourceGraphAtPage(resourcePlaceholderListDictionary, options.Page)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error while paginating & inflating resource graph: %v", err)
|
||||
}
|
||||
|
@ -215,7 +216,7 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
SourceID: resource.SourceID.String(),
|
||||
UserID: resource.UserID.String(),
|
||||
})
|
||||
sr.Logger.Debugf("populating resourcePlaceholder: %s", vertexId)
|
||||
gr.Logger.Debugf("populating resourcePlaceholder: %s", vertexId)
|
||||
|
||||
resource.RelatedResource = []*models.ResourceBase{}
|
||||
|
||||
|
@ -226,9 +227,9 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
//skip the current resourcePlaceholder if it's referenced in this list.
|
||||
//also skip the current resourcePlaceholder if its a Binary resourcePlaceholder (which is a special case)
|
||||
if vertexId != resourceVertexId(relatedResourcePlaceholder) && relatedResourcePlaceholder.ResourceType != "Binary" {
|
||||
relatedResource, err := sr.GetResourceByResourceTypeAndId(ctx, relatedResourcePlaceholder.ResourceType, relatedResourcePlaceholder.ResourceID)
|
||||
relatedResource, err := gr.GetResourceByResourceTypeAndId(ctx, relatedResourcePlaceholder.ResourceType, relatedResourcePlaceholder.ResourceID)
|
||||
if err != nil {
|
||||
sr.Logger.Warnf("ignoring, cannot safely handle error which occurred while getting related resource: %v", err)
|
||||
gr.Logger.Warnf("ignoring, cannot safely handle error which occurred while getting related resource: %v", err)
|
||||
return true
|
||||
}
|
||||
resource.RelatedResource = append(
|
||||
|
@ -268,9 +269,9 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
vertexId := resourceKeysVertexId(currentResource.SourceID.String(), currentResource.SourceResourceType, currentResource.SourceResourceID)
|
||||
for relatedVertexId, _ := range adjacencyMap[vertexId] {
|
||||
relatedResourcePlaceholder, _ := g.Vertex(relatedVertexId)
|
||||
relatedResourceFhir, err := sr.GetResourceByResourceTypeAndId(ctx, relatedResourcePlaceholder.ResourceType, relatedResourcePlaceholder.ResourceID)
|
||||
relatedResourceFhir, err := gr.GetResourceByResourceTypeAndId(ctx, relatedResourcePlaceholder.ResourceType, relatedResourcePlaceholder.ResourceID)
|
||||
if err != nil {
|
||||
sr.Logger.Warnf("ignoring, cannot safely handle error which occurred while getting related resource (flatten=false): %v", err)
|
||||
gr.Logger.Warnf("ignoring, cannot safely handle error which occurred while getting related resource (flatten=false): %v", err)
|
||||
continue
|
||||
}
|
||||
flattenRelatedResourcesFn(relatedResourceFhir)
|
||||
|
@ -295,7 +296,7 @@ func (sr *SqliteRepository) GetFlattenedResourceGraph(ctx context.Context, graph
|
|||
// - sort the root resources by date, desc
|
||||
// - use the page number + page size to determine which root resources to return
|
||||
// - return a dictionary of "source" resource lists
|
||||
func (sr *SqliteRepository) InflateResourceGraphAtPage(resourcePlaceholderListDictionary map[string][]*VertexResourcePlaceholder, page int) (map[string][]*models.ResourceBase, int, error) {
|
||||
func (gr *GormRepository) InflateResourceGraphAtPage(resourcePlaceholderListDictionary map[string][]*VertexResourcePlaceholder, page int) (map[string][]*models.ResourceBase, int, error) {
|
||||
totalElements := 0
|
||||
// Step 3a: since we cant calulate the sort order until the resources are loaded, we need to load all the root resources first.
|
||||
|
||||
|
@ -319,7 +320,7 @@ func (sr *SqliteRepository) InflateResourceGraphAtPage(resourcePlaceholderListDi
|
|||
return nil, totalElements, err
|
||||
}
|
||||
var tableWrappedResourceModels []models.ResourceBase
|
||||
sr.GormClient.
|
||||
gr.GormClient.
|
||||
Where("(user_id, source_id, source_resource_type, source_resource_id) IN ?", selectList).
|
||||
Table(tableName).
|
||||
Find(&tableWrappedResourceModels)
|
||||
|
@ -351,15 +352,15 @@ func (sr *SqliteRepository) InflateResourceGraphAtPage(resourcePlaceholderListDi
|
|||
return resourceListDictionary, totalElements, nil
|
||||
}
|
||||
|
||||
//We need to support the following types of graphs:
|
||||
// We need to support the following types of graphs:
|
||||
// - Medical History
|
||||
// - AddressBook (contacts)
|
||||
// - Medications
|
||||
// - Billing Report
|
||||
//edges are always "strongly connected", however "source" nodes (roots, like Condition or Encounter -- depending on ) are only one way.
|
||||
//add an edge from every resource to its related resource. Keep in mind that FHIR resources may not contain reciprocal edges, so we ensure the graph is rooted by flipping any
|
||||
//related resources that are "Condition" or "Encounter"
|
||||
func (sr *SqliteRepository) PopulateGraphTypeReciprocalRelationships(graphType pkg.ResourceGraphType, relationships []models.RelatedResource) []models.RelatedResource {
|
||||
// edges are always "strongly connected", however "source" nodes (roots, like Condition or Encounter -- depending on ) are only one way.
|
||||
// add an edge from every resource to its related resource. Keep in mind that FHIR resources may not contain reciprocal edges, so we ensure the graph is rooted by flipping any
|
||||
// related resources that are "Condition" or "Encounter"
|
||||
func (gr *GormRepository) PopulateGraphTypeReciprocalRelationships(graphType pkg.ResourceGraphType, relationships []models.RelatedResource) []models.RelatedResource {
|
||||
reciprocalRelationships := []models.RelatedResource{}
|
||||
|
||||
//prioritized lists of sources and sinks for the graph. We will use these to determine which resources are "root" nodes.
|
||||
|
@ -469,7 +470,7 @@ func getSourcesAndSinksForGraphType(graphType pkg.ResourceGraphType) ([][]string
|
|||
return sources, sinks, sourceFlattenRelated
|
||||
}
|
||||
|
||||
//source resource types are resources that are at the root of the graph, nothing may reference them directly
|
||||
// source resource types are resources that are at the root of the graph, nothing may reference them directly
|
||||
// loop though the list of source resource types, and see if the checkResourceType is one of them
|
||||
func foundResourceGraphSource(checkResourceType string, sourceResourceTypes [][]string) int {
|
||||
found := -1
|
||||
|
@ -482,7 +483,7 @@ func foundResourceGraphSource(checkResourceType string, sourceResourceTypes [][]
|
|||
return found
|
||||
}
|
||||
|
||||
//sink resource types are the leaves of the graph, they must not reference anything else. (only be referenced)
|
||||
// sink resource types are the leaves of the graph, they must not reference anything else. (only be referenced)
|
||||
func foundResourceGraphSink(checkResourceType string, sinkResourceTypes [][]string) int {
|
||||
found := -1
|
||||
for i, sinkResourceType := range sinkResourceTypes {
|
|
@ -3,6 +3,10 @@ package database
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
|
||||
databaseModel "github.com/fastenhealth/fasten-onprem/backend/pkg/models/database"
|
||||
"github.com/iancoleman/strcase"
|
||||
|
@ -10,9 +14,6 @@ import (
|
|||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/exp/slices"
|
||||
"gorm.io/gorm"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SearchParameterType string
|
||||
|
@ -52,9 +53,9 @@ const TABLE_ALIAS = "fhir"
|
|||
// )
|
||||
// AND (user_id = "6efcd7c5-3f29-4f0d-926d-a66ff68bbfc2")
|
||||
// GROUP BY `fhir`.`id`
|
||||
func (sr *SqliteRepository) QueryResources(ctx context.Context, query models.QueryResource) (interface{}, error) {
|
||||
func (gr *GormRepository) QueryResources(ctx context.Context, query models.QueryResource) (interface{}, error) {
|
||||
|
||||
sqlQuery, err := sr.sqlQueryResources(ctx, query)
|
||||
sqlQuery, err := gr.sqlQueryResources(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -74,7 +75,7 @@ func (sr *SqliteRepository) QueryResources(ctx context.Context, query models.Que
|
|||
|
||||
// see QueryResources
|
||||
// this function has all the logic, but should only be called directly for testing
|
||||
func (sr *SqliteRepository) sqlQueryResources(ctx context.Context, query models.QueryResource) (*gorm.DB, error) {
|
||||
func (gr *GormRepository) sqlQueryResources(ctx context.Context, query models.QueryResource) (*gorm.DB, error) {
|
||||
//todo, until we actually parse the select statement, we will just return all resources based on "from"
|
||||
|
||||
//SECURITY: this is required to ensure that only valid resource types are queried (since it's controlled by the user)
|
||||
|
@ -134,7 +135,7 @@ func (sr *SqliteRepository) sqlQueryResources(ctx context.Context, query models.
|
|||
}
|
||||
|
||||
//SECURITY: for safety, we will always add/override the current user_id to the where clause. This is to ensure that the user doesnt attempt to override this value in their own where clause
|
||||
currentUser, currentUserErr := sr.GetCurrentUser(ctx)
|
||||
currentUser, currentUserErr := gr.GetCurrentUser(ctx)
|
||||
if currentUserErr != nil {
|
||||
return nil, currentUserErr
|
||||
}
|
||||
|
@ -234,7 +235,7 @@ func (sr *SqliteRepository) sqlQueryResources(ctx context.Context, query models.
|
|||
fromClauses = lo.Uniq(fromClauses)
|
||||
fromClauses = lo.Compact(fromClauses)
|
||||
|
||||
sqlQuery := sr.GormClient.WithContext(ctx).
|
||||
sqlQuery := gr.GormClient.WithContext(ctx).
|
||||
Select(strings.Join(selectClauses, ", ")).
|
||||
Where(strings.Join(whereClauses, " AND "), whereNamedParameters).
|
||||
Group(groupClause).
|
||||
|
@ -253,7 +254,7 @@ func (sr *SqliteRepository) sqlQueryResources(ctx context.Context, query models.
|
|||
}
|
||||
|
||||
/// INTERNAL functionality. These functions are exported for testing, but are not available in the Interface
|
||||
//TODO: dont export these, instead use casting to convert the interface to the SqliteRepository struct, then call ehese functions directly
|
||||
//TODO: dont export these, instead use casting to convert the interface to the GormRepository struct, then call ehese functions directly
|
||||
|
||||
type SearchParameter struct {
|
||||
Name string
|
|
@ -3,6 +3,12 @@ package database
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
mock_config "github.com/fastenhealth/fasten-onprem/backend/pkg/config/mock"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/event_bus"
|
||||
|
@ -12,11 +18,6 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"gorm.io/gorm"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Define the suite, and absorb the built-in basic suite
|
||||
|
@ -42,6 +43,7 @@ func (suite *RepositorySqlTestSuite) BeforeTest(suiteName, testName string) {
|
|||
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -71,7 +73,7 @@ func TestRepositorySqlTestSuite(t *testing.T) {
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -108,7 +110,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL() {
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithMultipleWhereConditions() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -146,7 +148,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithMultipleWhereCon
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithPrimitiveOrderByAggregation() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -183,7 +185,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithPrimitiveOrderBy
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithKeywordOrderByAggregation() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -218,7 +220,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithKeywordOrderByAg
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithComplexOrderByAggregation() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -255,7 +257,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithComplexOrderByAg
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithPrimitiveCountByAggregation() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -292,7 +294,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithPrimitiveCountBy
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithKeywordCountByAggregation() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -329,7 +331,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithKeywordCountByAg
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithWildcardCountByAggregation() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -364,7 +366,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithWildcardCountByA
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithComplexCountByAggregation() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -401,7 +403,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithComplexCountByAg
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithComplexGroupByWithOrderByMaxFnAggregation() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -441,7 +443,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithComplexGroupByWi
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenGroupByNoModifier() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
||||
|
@ -478,7 +480,7 @@ func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenGroupByNoMo
|
|||
|
||||
func (suite *RepositorySqlTestSuite) TestQueryResources_SQL_WithTokenGroupByNoModifierWithLimit() {
|
||||
//setup
|
||||
sqliteRepo := suite.TestRepository.(*SqliteRepository)
|
||||
sqliteRepo := suite.TestRepository.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
|
@ -2,6 +2,10 @@ package database
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
mock_config "github.com/fastenhealth/fasten-onprem/backend/pkg/config/mock"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/event_bus"
|
||||
|
@ -9,9 +13,6 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// mimic tests from https://hl7.org/fhir/r4/search.html#token
|
||||
|
@ -259,6 +260,7 @@ func (suite *RepositoryTestSuite) TestQueryResources_SQL() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -270,7 +272,7 @@ func (suite *RepositoryTestSuite) TestQueryResources_SQL() {
|
|||
err = dbRepo.CreateUser(context.Background(), userModel)
|
||||
require.NoError(suite.T(), err)
|
||||
|
||||
sqliteRepo := dbRepo.(*SqliteRepository)
|
||||
sqliteRepo := dbRepo.(*GormRepository)
|
||||
sqliteRepo.GormClient = sqliteRepo.GormClient.Session(&gorm.Session{DryRun: true})
|
||||
|
||||
//test
|
|
@ -3,19 +3,20 @@ package database
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// LoadSettings will retrieve settings from the database, store them in the AppConfig object, and return a Settings struct
|
||||
func (sr *SqliteRepository) LoadUserSettings(ctx context.Context) (*models.UserSettings, error) {
|
||||
currentUser, currentUserErr := sr.GetCurrentUser(ctx)
|
||||
func (gr *GormRepository) LoadUserSettings(ctx context.Context) (*models.UserSettings, error) {
|
||||
currentUser, currentUserErr := gr.GetCurrentUser(ctx)
|
||||
if currentUserErr != nil {
|
||||
return nil, currentUserErr
|
||||
}
|
||||
|
||||
settingsEntries := []models.UserSettingEntry{}
|
||||
if err := sr.GormClient.
|
||||
if err := gr.GormClient.
|
||||
WithContext(ctx).
|
||||
Where(models.UserSettingEntry{
|
||||
UserID: currentUser.ID,
|
||||
|
@ -38,8 +39,8 @@ func (sr *SqliteRepository) LoadUserSettings(ctx context.Context) (*models.UserS
|
|||
// testing
|
||||
// curl -d '{"metrics": { "notify_level": 5, "status_filter_attributes": 5, "status_threshold": 5 }}' -H "Content-Type: application/json" -X POST http://localhost:9090/api/settings
|
||||
// SaveSettings will update settings in AppConfig object, then save the settings to the database.
|
||||
func (sr *SqliteRepository) SaveUserSettings(ctx context.Context, newSettings *models.UserSettings) error {
|
||||
currentUser, currentUserErr := sr.GetCurrentUser(ctx)
|
||||
func (gr *GormRepository) SaveUserSettings(ctx context.Context, newSettings *models.UserSettings) error {
|
||||
currentUser, currentUserErr := gr.GetCurrentUser(ctx)
|
||||
if currentUserErr != nil {
|
||||
return currentUserErr
|
||||
}
|
||||
|
@ -47,7 +48,7 @@ func (sr *SqliteRepository) SaveUserSettings(ctx context.Context, newSettings *m
|
|||
//retrieve current settings from the database
|
||||
currentSettingsEntries := []models.UserSettingEntry{}
|
||||
|
||||
if err := sr.GormClient.
|
||||
if err := gr.GormClient.
|
||||
WithContext(ctx).
|
||||
Where(models.UserSettingEntry{
|
||||
UserID: currentUser.ID,
|
||||
|
@ -66,8 +67,8 @@ func (sr *SqliteRepository) SaveUserSettings(ctx context.Context, newSettings *m
|
|||
for ndx, settingsEntry := range newSettingsEntries {
|
||||
|
||||
// store in database.
|
||||
//TODO: this should be `sr.gormClient.Updates(&settingsEntries).Error`
|
||||
err := sr.GormClient.
|
||||
//TODO: this should be `gr.gormClient.Updates(&settingsEntries).Error`
|
||||
err := gr.GormClient.
|
||||
WithContext(ctx).
|
||||
Model(&models.UserSettingEntry{}).
|
||||
Where([]uuid.UUID{settingsEntry.ID}).
|
||||
|
@ -80,7 +81,7 @@ func (sr *SqliteRepository) SaveUserSettings(ctx context.Context, newSettings *m
|
|||
return nil
|
||||
}
|
||||
|
||||
func (sr *SqliteRepository) PopulateDefaultUserSettings(ctx context.Context, userId uuid.UUID) error {
|
||||
func (gr *GormRepository) PopulateDefaultUserSettings(ctx context.Context, userId uuid.UUID) error {
|
||||
|
||||
//retrieve current settings from the database
|
||||
settingsEntries := []models.UserSettingEntry{}
|
||||
|
@ -92,6 +93,6 @@ func (sr *SqliteRepository) PopulateDefaultUserSettings(ctx context.Context, use
|
|||
SettingValueArray: []string{},
|
||||
})
|
||||
|
||||
return sr.GormClient.WithContext(ctx).Create(settingsEntries).Error
|
||||
return gr.GormClient.WithContext(ctx).Create(settingsEntries).Error
|
||||
|
||||
}
|
|
@ -3,6 +3,13 @@ package database
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
mock_config "github.com/fastenhealth/fasten-onprem/backend/pkg/config/mock"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/event_bus"
|
||||
|
@ -18,18 +25,12 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"golang.org/x/net/context"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSourceCredentialInterface(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
repo := new(SqliteRepository)
|
||||
repo := new(GormRepository)
|
||||
|
||||
//assert
|
||||
require.Implements(t, (*sourceModels.DatabaseRepository)(nil), repo, "should implement the DatabaseRepository interface from fasten-sources")
|
||||
|
@ -74,6 +75,7 @@ func (suite *RepositoryTestSuite) TestNewRepository() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
|
||||
//test
|
||||
|
@ -87,6 +89,7 @@ func (suite *RepositoryTestSuite) TestCreateUser() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -107,6 +110,7 @@ func (suite *RepositoryTestSuite) TestCreateUser_WithExitingUser_ShouldFail() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -135,6 +139,7 @@ func (suite *RepositoryTestSuite) TestCreateUser_WithUserProvidedId_ShouldBeRepl
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -160,6 +165,7 @@ func (suite *RepositoryTestSuite) TestGetUserByUsername() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -183,6 +189,7 @@ func (suite *RepositoryTestSuite) TestGetUserByUsername_WithInvalidUsername() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -205,6 +212,7 @@ func (suite *RepositoryTestSuite) TestGetCurrentUser_WithContextBackgroundAuthUs
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -229,6 +237,7 @@ func (suite *RepositoryTestSuite) TestGetCurrentUser_WithGinContextBackgroundAut
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -257,6 +266,7 @@ func (suite *RepositoryTestSuite) TestGetCurrentUser_WithContextBackgroundAuthUs
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -273,6 +283,7 @@ func (suite *RepositoryTestSuite) TestCreateGlossaryEntry() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -308,6 +319,7 @@ func (suite *RepositoryTestSuite) TestUpsertRawResource() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -364,6 +376,7 @@ func (suite *RepositoryTestSuite) TestUpsertRawResource_WithRelatedResourceAndDu
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -411,6 +424,7 @@ func (suite *RepositoryTestSuite) TestListResources() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -513,6 +527,7 @@ func (suite *RepositoryTestSuite) TestGetResourceByResourceTypeAndId() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -566,6 +581,7 @@ func (suite *RepositoryTestSuite) TestGetResourceBySourceId() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -619,6 +635,7 @@ func (suite *RepositoryTestSuite) TestGetPatientForSources() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -675,6 +692,7 @@ func (suite *RepositoryTestSuite) TestAddResourceAssociation() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -711,6 +729,7 @@ func (suite *RepositoryTestSuite) TestAddResourceAssociation_WithMismatchingSour
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -760,6 +779,7 @@ func (suite *RepositoryTestSuite) TestRemoveResourceAssociation() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -801,6 +821,7 @@ func (suite *RepositoryTestSuite) TestGetSourceSummary() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -881,6 +902,7 @@ func (suite *RepositoryTestSuite) TestGetSummary() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -984,6 +1006,7 @@ func (suite *RepositoryTestSuite) TestAddResourceComposition() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -1069,6 +1092,7 @@ func (suite *RepositoryTestSuite) TestAddResourceComposition_WithExistingComposi
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -1229,6 +1253,7 @@ func (suite *RepositoryTestSuite) TestCreateBackgroundJob_Sync() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -1263,6 +1288,7 @@ func (suite *RepositoryTestSuite) TestListBackgroundJobs() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
||||
|
@ -1339,6 +1365,7 @@ func (suite *RepositoryTestSuite) TestUpdateBackgroundJob() {
|
|||
//setup
|
||||
fakeConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
fakeConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
fakeConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
dbRepo, err := NewRepository(fakeConfig, logrus.WithField("test", suite.T().Name()), event_bus.NewNoopEventBusServer())
|
||||
require.NoError(suite.T(), err)
|
|
@ -0,0 +1,75 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/config"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/event_bus"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
|
||||
databaseModel "github.com/fastenhealth/fasten-onprem/backend/pkg/models/database"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func newPostgresRepository(appConfig config.Interface, globalLogger logrus.FieldLogger, eventBus event_bus.Interface) (DatabaseRepository, error) {
|
||||
//backgroundContext := context.Background()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Gorm/PostgreSQL setup
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
globalLogger.Infof("Trying to connect to postgres db: %s\n", appConfig.GetString("database.location"))
|
||||
dsn := appConfig.GetString("database.location")
|
||||
|
||||
database, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
|
||||
//TODO: figure out how to log database queries again.
|
||||
//logger: logger
|
||||
DisableForeignKeyConstraintWhenMigrating: true,
|
||||
})
|
||||
|
||||
if strings.ToUpper(appConfig.GetString("log.level")) == "DEBUG" {
|
||||
database = database.Debug() //set debug globally
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to connect to database! - %v", err)
|
||||
}
|
||||
globalLogger.Infof("Successfully connected to fasten postgres db: %s\n", dsn)
|
||||
|
||||
fastenRepo := GormRepository{
|
||||
AppConfig: appConfig,
|
||||
Logger: globalLogger,
|
||||
GormClient: database,
|
||||
EventBus: eventBus,
|
||||
}
|
||||
|
||||
//TODO: automigrate for now, this should be replaced with a migration tool once the DB has stabilized.
|
||||
err = fastenRepo.Migrate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//automigrate Fhir Resource Tables
|
||||
err = databaseModel.Migrate(fastenRepo.GormClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create/update admin user
|
||||
//TODO: determine if this admin user is ncessary
|
||||
//SECURITY: validate this user is necessary
|
||||
adminUser := models.User{}
|
||||
err = database.FirstOrCreate(&adminUser, models.User{Username: "admin"}).Error
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create admin user! - %v", err)
|
||||
}
|
||||
|
||||
//fail any Locked jobs. This is necessary because the job may have been locked by a process that was killed.
|
||||
err = fastenRepo.CancelAllLockedBackgroundJobsAndFail()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &fastenRepo, nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -17,3 +17,10 @@ type ConfigValidationError string
|
|||
func (str ConfigValidationError) Error() string {
|
||||
return fmt.Sprintf("ConfigValidationError: %q", string(str))
|
||||
}
|
||||
|
||||
// Raised when the database type is unsupported
|
||||
type DatabaseTypeNotSupportedError string
|
||||
|
||||
func (str DatabaseTypeNotSupportedError) Error() string {
|
||||
return fmt.Sprintf("DatabaseTypeNotSupportedError: %q", string(str))
|
||||
}
|
||||
|
|
|
@ -6,13 +6,17 @@ package main
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/dave/jennifer/jen"
|
||||
"github.com/iancoleman/strcase"
|
||||
"golang.org/x/exp/slices"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/dave/jennifer/jen"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/config"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/errors"
|
||||
"github.com/iancoleman/strcase"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type SearchParameter struct {
|
||||
|
@ -47,6 +51,22 @@ PLEASE DO NOT EDIT BY HAND
|
|||
`, "\n"), "\n")
|
||||
|
||||
func main() {
|
||||
// Read config file for database type
|
||||
appconfig, err := config.Create()
|
||||
if err != nil {
|
||||
fmt.Printf("FATAL: %+v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Find and read the config file
|
||||
err = appconfig.ReadConfig("../../../../config.yaml")
|
||||
if _, ok := err.(errors.ConfigFileMissingError); ok { // Handle errors reading the config file
|
||||
//ignore "could not find config file"
|
||||
} else if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
databaseType := appconfig.GetString("database.type")
|
||||
|
||||
// Read the search-parameters.json file
|
||||
searchParamsData, err := ioutil.ReadFile("search-parameters.json")
|
||||
if err != nil {
|
||||
|
@ -188,10 +208,18 @@ func main() {
|
|||
golangFieldStatement = g.Id(fieldName).Id(golangFieldType)
|
||||
}
|
||||
}
|
||||
golangFieldStatement.Tag(map[string]string{
|
||||
"json": fmt.Sprintf("%s,omitempty", strcase.ToLowerCamel(fieldName)),
|
||||
"gorm": fmt.Sprintf("column:%s;%s", strcase.ToLowerCamel(fieldName), mapGormType(fieldInfo.FieldType)),
|
||||
})
|
||||
|
||||
if databaseType == "sqlite" {
|
||||
golangFieldStatement.Tag(map[string]string{
|
||||
"json": fmt.Sprintf("%s,omitempty", strcase.ToLowerCamel(fieldName)),
|
||||
"gorm": fmt.Sprintf("column:%s;%s", strcase.ToLowerCamel(fieldName), mapGormTypeSqlite(fieldInfo.FieldType)),
|
||||
})
|
||||
} else {
|
||||
golangFieldStatement.Tag(map[string]string{
|
||||
"json": fmt.Sprintf("%s,omitempty", strcase.ToLowerCamel(fieldName)),
|
||||
"gorm": fmt.Sprintf("column:%s;%s", strcase.ToLowerCamel(fieldName), mapGormTypePostgres(fieldInfo.FieldType)),
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -663,7 +691,7 @@ func mapFieldType(fieldType string) string {
|
|||
}
|
||||
|
||||
// https://www.sqlite.org/datatype3.html
|
||||
func mapGormType(fieldType string) string {
|
||||
func mapGormTypeSqlite(fieldType string) string {
|
||||
// gorm:"type:text;serializer:json"
|
||||
|
||||
switch fieldType {
|
||||
|
@ -687,3 +715,26 @@ func mapGormType(fieldType string) string {
|
|||
return "type:text"
|
||||
}
|
||||
}
|
||||
|
||||
func mapGormTypePostgres(fieldType string) string {
|
||||
switch fieldType {
|
||||
case "number":
|
||||
return "type:real"
|
||||
case "token":
|
||||
return "type:text;serializer:json"
|
||||
case "reference":
|
||||
return "type:text;serializer:json"
|
||||
case "date":
|
||||
return "type:timestamptz"
|
||||
case "string":
|
||||
return "type:text;serializer:json"
|
||||
case "uri":
|
||||
return "type:text"
|
||||
case "special":
|
||||
return "type:text;serializer:json"
|
||||
case "quantity":
|
||||
return "type:text;serializer:json"
|
||||
default:
|
||||
return "type:text"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ func (suite *SourceHandlerTestSuite) BeforeTest(suiteName, testName string) {
|
|||
|
||||
appConfig := mock_config.NewMockInterface(suite.MockCtrl)
|
||||
appConfig.EXPECT().GetString("database.location").Return(suite.TestDatabase.Name()).AnyTimes()
|
||||
appConfig.EXPECT().GetString("database.type").Return("sqlite").AnyTimes()
|
||||
appConfig.EXPECT().GetString("log.level").Return("INFO").AnyTimes()
|
||||
suite.AppConfig = appConfig
|
||||
|
||||
|
|
|
@ -20,9 +20,10 @@ web:
|
|||
frontend:
|
||||
path: /opt/fasten/web
|
||||
database:
|
||||
location: '/opt/fasten/db/fasten.db'
|
||||
type: 'sqlite' # postgres also supported, but still experimental changes
|
||||
location: '/opt/fasten/db/fasten.db' # if postgres use a DSN, eg. `host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=required TimeZone=Asia/Shanghai`
|
||||
log:
|
||||
file: '' #absolute or relative paths allowed, eg. web.log
|
||||
file: '' # absolute or relative paths allowed, eg. web.log
|
||||
level: INFO
|
||||
jwt:
|
||||
issuer:
|
||||
|
|
9
go.mod
9
go.mod
|
@ -27,7 +27,13 @@ require (
|
|||
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17
|
||||
golang.org/x/net v0.14.0
|
||||
gorm.io/datatypes v1.0.7
|
||||
gorm.io/gorm v1.24.1
|
||||
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.4.3 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -104,6 +110,7 @@ require (
|
|||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gorm.io/driver/mysql v1.3.2 // indirect
|
||||
gorm.io/driver/postgres v1.5.3
|
||||
modernc.org/libc v1.19.0 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.4.0 // indirect
|
||||
|
|
8
go.sum
8
go.sum
|
@ -470,6 +470,8 @@ github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5
|
|||
github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
|
@ -482,6 +484,8 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ
|
|||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w=
|
||||
github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw=
|
||||
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
|
@ -1286,6 +1290,8 @@ gorm.io/driver/mysql v1.3.2 h1:QJryWiqQ91EvZ0jZL48NOpdlPdMjdip1hQ8bTgo4H7I=
|
|||
gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
|
||||
gorm.io/driver/postgres v1.3.4 h1:evZ7plF+Bp+Lr1mO5NdPvd6M/N98XtwHixGB+y7fdEQ=
|
||||
gorm.io/driver/postgres v1.3.4/go.mod h1:y0vEuInFKJtijuSGu9e5bs5hzzSzPK+LancpKpvbRBw=
|
||||
gorm.io/driver/postgres v1.5.3 h1:qKGY5CPHOuj47K/VxbCXJfFvIUeqMSXXadqdCY+MbBU=
|
||||
gorm.io/driver/postgres v1.5.3/go.mod h1:F+LtvlFhZT7UBiA81mC9W6Su3D4WUhSboc/36QZU0gk=
|
||||
gorm.io/driver/sqlite v1.3.1 h1:bwfE+zTEWklBYoEodIOIBwuWHpnx52Z9zJFW5F33WLk=
|
||||
gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg=
|
||||
gorm.io/driver/sqlserver v1.3.1 h1:F5t6ScMzOgy1zukRTIZgLZwKahgt3q1woAILVolKpOI=
|
||||
|
@ -1295,6 +1301,8 @@ gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
|||
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gorm.io/gorm v1.24.1 h1:CgvzRniUdG67hBAzsxDGOAuq4Te1osVMYsa1eQbd4fs=
|
||||
gorm.io/gorm v1.24.1/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55 h1:sC1Xj4TYrLqg1n3AN10w871An7wJM0gzgcm8jkIkECQ=
|
||||
gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
Loading…
Reference in New Issue