1
1
"use server" ;
2
2
3
3
import { getDbClient } from "./dbClient" ;
4
- import { QueryDetailsResult } from "../queryBuilding/utils" ;
4
+ import { NestedQuery , QueryDetailsResult } from "../queryBuilding/utils" ;
5
+ import { DibbsValueSet } from "../constants" ;
6
+ import { DEFAULT_TIME_WINDOW } from "../utils" ;
7
+ import { randomUUID } from "crypto" ;
5
8
const dbClient = getDbClient ( ) ;
6
9
7
10
/**
@@ -28,3 +31,87 @@ export async function getSavedQueryDetails(queryId: string) {
28
31
console . error ( "Error retrieving query" , error ) ;
29
32
}
30
33
}
34
+
35
+ /**
36
+ * Backend handler function for upserting a query
37
+ * @param queryInput - frontend input for a query
38
+ * @param queryName - name of query
39
+ * @param author - author
40
+ * @param queryId - a queryId if previously defined
41
+ * @returns - all columns of the newly added row in the query table
42
+ */
43
+ export async function saveCustomQuery (
44
+ queryInput : NestedQuery ,
45
+ queryName : string ,
46
+ author : string ,
47
+ queryId ?: string ,
48
+ ) {
49
+ const queryString = `
50
+ INSERT INTO query
51
+ values($1, $2, $3, $4, $5, $6, $7, $8, $9)
52
+ ON CONFLICT(id)
53
+ DO UPDATE SET
54
+ query_name = EXCLUDED.query_name,
55
+ conditions_list = EXCLUDED.conditions_list,
56
+ query_data = EXCLUDED.query_data,
57
+ author = EXCLUDED.author,
58
+ date_last_modified = EXCLUDED.date_last_modified
59
+ RETURNING id, query_name;
60
+ ` ;
61
+ const { queryDataInsert, conditionInsert } =
62
+ formatQueryDataForDatabase ( queryInput ) ;
63
+
64
+ const NOW = new Date ( ) . toISOString ( ) ;
65
+ try {
66
+ const dataToWrite = [
67
+ queryId ? queryId : randomUUID ( ) ,
68
+ queryName ,
69
+ queryDataInsert ,
70
+ conditionInsert ,
71
+ author ,
72
+ NOW ,
73
+ NOW ,
74
+ DEFAULT_TIME_WINDOW . timeWindowNumber ,
75
+ DEFAULT_TIME_WINDOW . timeWindowUnit ,
76
+ ] ;
77
+ const result = await dbClient . query ( queryString , dataToWrite ) ;
78
+ if ( result . rows . length > 0 ) {
79
+ return result . rows as unknown as QueryDetailsResult [ ] ;
80
+ }
81
+ console . error ( "Query save failed:" , dataToWrite ) ;
82
+ return [ ] ;
83
+ } catch ( error ) {
84
+ console . error ( "Error saving new query" , error ) ;
85
+ }
86
+ }
87
+
88
+ function formatQueryDataForDatabase ( frontendInput : NestedQuery ) {
89
+ const queryData : Record < string , { [ valueSetId : string ] : DibbsValueSet } > = { } ;
90
+ const conditionIds : string [ ] = [ ] ;
91
+
92
+ Object . entries ( frontendInput ) . forEach ( ( [ conditionId , data ] ) => {
93
+ queryData [ conditionId ] = { } ;
94
+ conditionIds . push ( conditionId ) ;
95
+ Object . values ( data ) . forEach ( ( dibbsVsMap ) => {
96
+ Object . entries ( dibbsVsMap ) . forEach ( ( [ vsId , dibbsVs ] ) => {
97
+ queryData [ conditionId ] [ vsId ] = dibbsVs ;
98
+ } ) ;
99
+ } ) ;
100
+ } ) ;
101
+
102
+ return {
103
+ queryDataInsert : queryData ,
104
+ conditionInsert : formatConditionsForPostgres ( conditionIds ) ,
105
+ } ;
106
+ }
107
+
108
+ function formatConditionsForPostgres ( arr : string [ ] ) : string {
109
+ if ( arr . length === 0 ) return "{}" ;
110
+
111
+ const escapedStrings = arr . map ( ( str ) => {
112
+ const escaped = str . replace ( / " / g, '\\"' ) ;
113
+ return `"${ escaped } "` ;
114
+ } ) ;
115
+
116
+ return `{${ escapedStrings . join ( "," ) } }` ;
117
+ }
0 commit comments