Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance when getting a project's related resources #592

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 9 additions & 83 deletions internal/api/v2/projects_related_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ type ProjectRelatedResourcesGetResponseHermesDocument struct {
DocumentNumber string `json:"documentNumber"`
ModifiedTime int64 `json:"modifiedTime"`
Owners []string `json:"owners"`
OwnerPhotos []string `json:"ownerPhotos,omitempty"`
Product string `json:"product"`
SortOrder int `json:"sortOrder"`
Status string `json:"status"`
Expand Down Expand Up @@ -77,25 +76,12 @@ func projectsResourceRelatedResourcesHandler(
case "GET":
logArgs = append(logArgs, "method", r.Method)

// Get project.
proj := models.Project{}
if err := proj.Get(srv.DB, projectID); err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
srv.Logger.Warn("project not found", logArgs...)
http.Error(w, "Project not found", http.StatusNotFound)
return
} else {
srv.Logger.Error("error getting project from database",
append([]interface{}{
"error", err,
}, logArgs...)...)
http.Error(
w, "Error processing request", http.StatusInternalServerError)
return
}
// Get project's typed related resources.
proj := models.Project{
Model: gorm.Model{
ID: projectID,
},
}

// Get typed related resources.
elrrs, hdrrs, err := proj.GetRelatedResources(srv.DB)
if err != nil {
srv.Logger.Error("error getting related resources",
Expand All @@ -114,17 +100,6 @@ func projectsResourceRelatedResourcesHandler(
}
// Add external link related resources.
for _, elrr := range elrrs {
if err := elrr.Get(srv.DB); err != nil {
srv.Logger.Error(
"error getting external link related resource from database",
append([]interface{}{
"error", err,
}, logArgs...)...)
http.Error(
w, "Error processing request", http.StatusInternalServerError)
return
}

resp.ExternalLinks = append(resp.ExternalLinks,
ProjectRelatedResourcesGetResponseExternalLink{
Name: elrr.Name,
Expand All @@ -135,40 +110,10 @@ func projectsResourceRelatedResourcesHandler(
// Add Hermes document related resources.
for _, hdrr := range hdrrs {
logArgs = append(logArgs, "document_id", hdrr.Document.GoogleFileID)

// Get document from database.
model := models.Document{
GoogleFileID: hdrr.Document.GoogleFileID,
}
if err := model.Get(srv.DB); err != nil {
srv.Logger.Error("error getting document from database",
append([]interface{}{
"error", err,
}, logArgs...)...)
http.Error(
w, "Error processing request", http.StatusInternalServerError)
return
}

// Get reviews for the document.
var reviews models.DocumentReviews
if err := reviews.Find(srv.DB, models.DocumentReview{
Document: models.Document{
GoogleFileID: hdrr.Document.GoogleFileID,
},
}); err != nil {
srv.Logger.Error("error getting reviews for document",
append([]interface{}{
"error", err,
}, logArgs...)...)
http.Error(
w, "Error processing request", http.StatusInternalServerError)
return
}

// Convert database model to a document.
// Convert database model to a document. We don't need document review
// data for this endpoint.
doc, err := document.NewFromDatabaseModel(
model, reviews)
hdrr.Document, models.DocumentReviews{})
if err != nil {
srv.Logger.Error("error converting database model to document type",
append([]interface{}{
Expand All @@ -179,35 +124,16 @@ func projectsResourceRelatedResourcesHandler(
return
}

// Get owner photo by searching Google Workspace directory.
if len(doc.Owners) > 0 {
ppl, err := srv.GWService.SearchPeople(doc.Owners[0], "photos")
if err != nil {
// Log but don't return an error.
srv.Logger.Error("error searching directory for person",
append([]interface{}{
"error", err,
"person", doc.Owners[0],
}, logArgs...)...)
}
if len(ppl) > 0 {
if len(ppl[0].Photos) > 0 {
doc.OwnerPhotos = []string{ppl[0].Photos[0].Url}
}
}
}

resp.HermesDocuments = append(
resp.HermesDocuments,
ProjectRelatedResourcesGetResponseHermesDocument{
GoogleFileID: hdrr.Document.GoogleFileID,
GoogleFileID: doc.ObjectID,
Title: doc.Title,
CreatedTime: doc.CreatedTime,
DocumentType: doc.DocType,
DocumentNumber: doc.DocNumber,
ModifiedTime: doc.ModifiedTime,
Owners: doc.Owners,
OwnerPhotos: doc.OwnerPhotos,
Product: doc.Product,
SortOrder: hdrr.RelatedResource.SortOrder,
Status: doc.Status,
Expand Down
62 changes: 27 additions & 35 deletions pkg/models/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,43 +139,35 @@ func (p *Project) GetRelatedResources(db *gorm.DB) (
return nil, nil, err
}

// Get the project.
if err := p.Get(db, p.ID); err != nil {
return nil, nil, fmt.Errorf("error getting project: %w", err)
// Find external link related resources.
if err := db.
Model(&ProjectRelatedResourceExternalLink{}).
Joins("JOIN project_related_resources ON project_related_resources.related_resource_id = project_related_resource_external_links.id").
Where("project_related_resources.project_id = ? AND project_related_resources.related_resource_type = ?",
p.ID, "project_related_resource_external_links").
Preload(clause.Associations).
Find(&elrrs).
Error; err != nil {
return nil,
nil,
fmt.Errorf("error getting external link related resources: %w", err)
}

// Get related resources.
for _, rr := range p.RelatedResources {
switch rr.RelatedResourceType {
case "project_related_resource_external_links":
elrr := ProjectRelatedResourceExternalLink{}
if err := db.
Where("id = ?", rr.RelatedResourceID).
Preload(clause.Associations).
First(&elrr).Error; err != nil {
return nil,
nil,
fmt.Errorf("error getting external link related resource: %w", err)
}
elrrs = append(elrrs, elrr)
case "project_related_resource_hermes_documents":
hdrr := ProjectRelatedResourceHermesDocument{}
if err := db.
Where("id = ?", rr.RelatedResourceID).
Preload(clause.Associations).
First(&hdrr).Error; err != nil {
return nil,
nil,
fmt.Errorf(
"error getting document for Hermes document related resource: %w",
err)
}
hdrrs = append(hdrrs, hdrr)
default:
return nil,
nil,
fmt.Errorf("unknown related resource type: %s", rr.RelatedResourceType)
}
// Find Hermes document related resources.
if err := db.
Model(&ProjectRelatedResourceHermesDocument{}).
Joins("JOIN project_related_resources ON project_related_resources.related_resource_id = project_related_resource_hermes_documents.id").
Where("project_related_resources.project_id = ? AND project_related_resources.related_resource_type = ?",
p.ID, "project_related_resource_hermes_documents").
Preload(clause.Associations).
Preload("Document.DocumentType").
Preload("Document.Owner").
Preload("Document.Product").
Find(&hdrrs).
Error; err != nil {
return nil,
nil,
fmt.Errorf("error getting Hermes document related resources: %w", err)
}

return
Expand Down
Loading