@@ -14,11 +14,11 @@ import (
1414 "math/rand"
1515 "os"
1616 "reflect"
17- "regexp"
1817 "sort"
1918 "strings"
2019 "sync"
2120 "time"
21+ "regexp"
2222
2323 "encoding/base64"
2424 "gopkg.in/yaml.v3"
@@ -59,6 +59,8 @@ func getRootFolder() string {
5959 return rootFolder
6060}
6161
62+
63+
6264func SaveQuery (inputStandard , gptTranslated string , shuffleConfig ShuffleConfig ) error {
6365 if len (shuffleConfig .URL ) > 0 {
6466 //return nil
@@ -95,8 +97,10 @@ func GptTranslate(keyTokenFile, standardFormat, inputDataFormat string, shuffleC
9597 systemMessage := fmt .Sprintf (`Translate the given user input JSON structure to the provided standard format in the jq format. Use the values from the standard to guide you what to look for. Ensure the output is valid JSON, and does NOT add more keys to the standard. Make sure each important key from the user input is in the standard. Empty fields in the standard are ok. If values are nested, ALWAYS add the nested value in jq format such as 'secret.version.value'. %sExample: If the standard is '{"id": "The id of the ticket", "title": "The ticket title"}', and the user input is '{"key": "12345", "fields:": {"id": "1234", "summary": "The title of the ticket"}}', the output should be '{"id": "key", "title": "fields.summary"}'. ALWAYS go deeper than the top level of the User Input and choose accurate values like "fields.id" instead of just "fields" where it fits.
9698
9799Additional formatting rules:
100+ - jq formatting for loops is ok
98101- Add a dollar sign in front of every translation: $key.subkey.subsubkey
99102- If it makes sense, you can add multiple variables in the middle of descriptive text such as 'The ticket $data.id with title $data.title has been created'
103+ - If the type is an Array, make it an actual JSON array with all the relevant keys. Example: Array type 'firstname & lastname' becomes [{"firstname": "$data[].firstname", "lastname": "$data[].lastname"}]
100104` , additionalCondition )
101105 // If translation is needed, you may use Liquid.
102106
@@ -236,6 +240,105 @@ func LiquidTranslate(ctx context.Context, userInput, translatedInput []byte) ([]
236240 return []byte (out ), nil
237241}
238242
243+ type Valuereplace struct {
244+ Key string `json:"key" datastore:"key" yaml:"key"`
245+ Value string `json:"value" datastore:"value,noindex" yaml:"value"`
246+
247+ // Used for e.g. user input storage
248+ Answer string `json:"answer,omitempty" datastore:"answer,noindex" yaml:"answer,omitempty"`
249+ }
250+
251+ // Fixes potential decision return or reference problems:
252+ // {{list_tickets}} -> $list_tickets
253+ // {{list_tickets[0].description}} -> $list_tickets.#0.description
254+ // {{ticket.description}} -> $ticket.description
255+ func TranslateBadFieldFormats (fields []Valuereplace , skipLiquid ... bool ) []Valuereplace {
256+ skipLiquidCheck := false
257+ if len (skipLiquid ) > 0 && skipLiquid [0 ] {
258+ skipLiquidCheck = true
259+ }
260+
261+ for fieldIndex , _ := range fields {
262+ field := fields [fieldIndex ]
263+ if ! skipLiquidCheck && (! strings .Contains (field .Value , "{{" ) || ! strings .Contains (field .Value , "}}" )) {
264+ log .Printf ("[DEBUG] Schemaless: No Liquid format found in field value '%s', skipping." , field .Value )
265+ continue
266+ }
267+
268+ // App SDK pattern
269+ //matchPattern := `([$]{1}([a-zA-Z0-9_@-]+\.?){1}([a-zA-Z0-9#_@-]+\.?){0,})`
270+
271+ // Used for testing
272+ re := regexp .MustCompile (`{{\s*([a-zA-Z0-9_\.]+)(\[[0-9]*\])?(\.[a-zA-Z0-9_]+)?\s*}}` )
273+ if skipLiquidCheck {
274+ //re = regexp.MustCompile(`\s*([a-zA-Z0-9_\.]+)(\[[0-9]*\])?(\.[a-zA-Z0-9_]+)?\s*`)
275+ }
276+
277+ matches := re .FindAllStringSubmatch (field .Value , - 1 )
278+ if len (matches ) == 0 {
279+ continue
280+ }
281+
282+ stringBuild := "$"
283+ for _ , match := range matches {
284+ log .Printf ("MATCH: %#v" , match )
285+
286+ for i , matchValue := range match {
287+ if i == 0 {
288+ continue
289+ }
290+
291+ if i != 1 {
292+ if len (matchValue ) > 0 && ! strings .HasPrefix (matchValue , "." ) {
293+ stringBuild += "."
294+ }
295+ }
296+
297+ if strings .HasPrefix (matchValue , "[" ) && strings .HasSuffix (matchValue , "]" ) {
298+ // Find the formats:
299+ // [] -> #
300+ // [:] -> #
301+ // [0] -> #0
302+ // [0:1] -> #0-1
303+ // [0:] -> #0-max
304+ if matchValue == "[]" || matchValue == "[:]" {
305+ stringBuild += "#"
306+ } else if strings .Contains (matchValue , ":" ) {
307+ parts := strings .Split (matchValue , ":" )
308+ if len (parts ) == 2 {
309+ stringBuild += fmt .Sprintf ("#%s-%s" , parts [0 ], parts [1 ])
310+ } else {
311+ stringBuild += fmt .Sprintf ("#%s-max" , parts [0 ])
312+ }
313+
314+ stringBuild += fmt .Sprintf ("#%s" , matchValue )
315+ } else {
316+ // Remove the brackets
317+ matchValue = strings .ReplaceAll (matchValue , "[" , "" )
318+ matchValue = strings .ReplaceAll (matchValue , "]" , "" )
319+ stringBuild += fmt .Sprintf ("#%s" , matchValue )
320+ }
321+
322+ continue
323+ }
324+
325+ stringBuild += matchValue
326+ }
327+
328+ log .Printf ("VALUE: %#v" , field .Value )
329+ if len (match ) > 1 {
330+ field .Value = strings .ReplaceAll (field .Value , match [0 ], stringBuild )
331+ fields [fieldIndex ].Value = field .Value
332+ //log.Printf("VALUE: %#v", field.Value)
333+ }
334+
335+ stringBuild = "$"
336+ }
337+ }
338+
339+ return fields
340+ }
341+
239342func GetStructureFromCache (ctx context.Context , inputKeyToken string ) (map [string ]interface {}, error ) {
240343 // Making sure it's not too long
241344 inputKeyTokenMd5 := fmt .Sprintf ("%x" , md5 .Sum ([]byte (inputKeyToken )))
@@ -811,6 +914,7 @@ func recurseFindKey(input map[string]interface{}, key string, depth int) (string
811914 log .Printf ("[ERROR] Schemaless reverse (11): Error marshalling list value: %v" , err )
812915 }
813916
917+
814918 // Checks if we are supposed to check the list or not
815919 if len (parsedKey ) > 0 && string (parsedKey [0 ]) == "#" {
816920 // Trim until first dot (.)
@@ -860,7 +964,8 @@ func recurseFindKey(input map[string]interface{}, key string, depth int) (string
860964
861965 // If we get them recursed with .#.#
862966 if len (marshalled ) > 2 {
863- return "schemaless_list" + string (marshalled ), nil
967+ toReturn := fmt .Sprintf ("schemaless_list%s" , string (marshalled ))
968+ return toReturn , nil
864969 } else {
865970 return "" , nil
866971 }
@@ -976,12 +1081,17 @@ func handleMultiListItems(translatedInput []interface{}, parentKey string, parse
9761081 // strings -> build it out.
9771082 //for childKey, v := range parsedValues {
9781083
979- log .Printf ("\n \n \n STARTING NEW LIST\n \n \n " )
1084+ if debug {
1085+ log .Printf ("\n \n [DEBUG] STARTING NEW LIST\n \n " )
1086+ }
1087+
9801088 newParsedValues := parsedValues
9811089 for childKey , _ := range newParsedValues {
982- log .Printf ("\n \n CHILDKEY START (%d): %#v\n \n " , childIndex , childKey )
983- v := parsedValues [childKey ]
1090+ if debug {
1091+ log .Printf ("[DEBUG] CHILDKEY START (%d): %#v" , childIndex , childKey )
1092+ }
9841093
1094+ v := parsedValues [childKey ]
9851095 if val , ok := v .(map [string ]interface {}); ok {
9861096 // By passing in translatedInput we allow child objects to modify the parent?
9871097 newKey := fmt .Sprintf ("%s.%s" , parentKey , childKey )
@@ -1000,17 +1110,48 @@ func handleMultiListItems(translatedInput []interface{}, parentKey string, parse
10001110 }
10011111
10021112 } else if val , ok := v .(string ); ok {
1113+
1114+ // Handle list expansion
10031115 if strings .Contains (val , "schemaless_list[" ) {
1004- //if val == "schemaless_list[]" || val == "schemaless_list" {
1005- //}
10061116
10071117 foundList := strings .Split (val , "schemaless_list" )
10081118 if len (foundList ) >= 2 {
10091119
10101120 // Somehow ALWAYS look for the first INNER list
10111121 // This makes it so that extrapolation can be done well across all fields everywhere
1012-
10131122 matchingList := strings .Join (foundList [1 :], "schemaless_list" )
1123+ newListStr := ""
1124+
1125+ recording := false
1126+ bracketCount := 0
1127+ for _ , matchChar := range matchingList {
1128+ if matchChar == '[' {
1129+ recording = true
1130+ bracketCount += 1
1131+ if bracketCount == 1 {
1132+ //continue
1133+ }
1134+ }
1135+
1136+ if recording {
1137+ newListStr += string (matchChar )
1138+ }
1139+
1140+ if matchChar == ']' {
1141+ bracketCount -= 1
1142+ if bracketCount == 0 {
1143+ recording = false
1144+ break
1145+ }
1146+ }
1147+
1148+
1149+ }
1150+
1151+ if strings .HasPrefix (newListStr , "[" ) && strings .HasSuffix (newListStr , "]" ) {
1152+ matchingList = newListStr
1153+ }
1154+
10141155 unmarshalledList := []string {}
10151156 err := json .Unmarshal ([]byte (matchingList ), & unmarshalledList )
10161157 if err != nil {
@@ -1061,17 +1202,30 @@ func handleMultiListItems(translatedInput []interface{}, parentKey string, parse
10611202 newModList := modificationList [cnt ].(map [string ]interface {})
10621203 marshalledMap , err := json .Marshal (newModList )
10631204 if err == nil {
1064- comparisonString := fmt .Sprintf (`"%s":"schemaless_list[` , newKey )
1065- if ! strings .Contains (string (marshalledMap ), comparisonString ) {
1066- continue
1205+ // FIXME: This part is going wrong with additional items in there
1206+ //comparisonString := fmt.Sprintf(`"%s":"schemaless_list[`, newKey)
1207+ //if !strings.Contains(string(marshalledMap), comparisonString) {
1208+
1209+ if strings .Contains (string (marshalledMap ), fmt .Sprintf (`"%s":"` , newKey )) && strings .Contains (string (marshalledMap ), `schemaless_list[` ) {
1210+ // Replace the schemaless_list[...] part with the listValue
1211+ listValue = strings .Replace (val , fmt .Sprintf ("schemaless_list%s" , matchingList ), listValue , 1 )
10671212
1213+ } else {
1214+ continue
10681215 }
10691216
1070- log .Printf ("Listvalue to put '%s' in key '%s': %s" , listValue , newKey , string (marshalledMap ))
1217+ if debug {
1218+ log .Printf ("[DEBUG] Listvalue to put '%s' in key '%s': %s" , listValue , newKey , string (marshalledMap ))
1219+ }
1220+ } else {
1221+ log .Printf ("[ERROR] Schemaless: Error marshalling map during list handling: %v" , err )
10711222 }
10721223
10731224 newModList , _ = setNestedMap (newModList , newKey , listValue )
1074- log .Printf ("NEW VALUE: %#v" , newModList )
1225+ if debug {
1226+ log .Printf ("[DEBUG] NEW VALUE: %#v" , newModList )
1227+ }
1228+
10751229 modificationList [cnt ] = newModList
10761230 updated = true
10771231 //break
@@ -1084,7 +1238,9 @@ func handleMultiListItems(translatedInput []interface{}, parentKey string, parse
10841238 }
10851239
10861240 marshalled , _ := json .MarshalIndent (modificationList , "" , "\t " )
1087- log .Printf ("MARSHALLED (%d): %s." , listDepth , string (marshalled ))
1241+ if debug {
1242+ log .Printf ("[DEBUG] MARSHALLED (%d): %s." , listDepth , string (marshalled ))
1243+ }
10881244
10891245 if listDepth > 0 {
10901246 // Updates the child & here
@@ -1276,7 +1432,6 @@ func runJsonTranslation(ctx context.Context, inputValue []byte, translation map[
12761432 continue
12771433 }
12781434
1279- // Runs an actual translation
12801435 output , _ , err := runJsonTranslation (ctx , inputValue , newValue )
12811436 if err != nil {
12821437 log .Printf ("[ERROR] Schemaless: Error in runJsonTranslation for key '%s': %v" , translationKey , err )
@@ -1298,6 +1453,10 @@ func runJsonTranslation(ctx context.Context, inputValue []byte, translation map[
12981453 // Hard to optimise for subkeys -> parent control tho
12991454 if strings .Contains (string (output ), "schemaless_list[" ) {
13001455 //newTranslatedInput := handleMultiListItems(newOutput, translationKey, outputParsed)
1456+ if debug {
1457+ log .Printf ("\n \n \n LIST: %s\n \n \n " , string (output ))
1458+ }
1459+
13011460 newTranslatedInput := handleMultiListItems (newOutput , "" , outputParsed , 0 , 0 )
13021461 translationValue = newTranslatedInput
13031462
@@ -1347,7 +1506,21 @@ func runJsonTranslation(ctx context.Context, inputValue []byte, translation map[
13471506 translatedInput [translationKey ] = translationValueParsed
13481507
13491508 } else if val , ok := translationValue .(string ); ok {
1350- log .Printf ("[DEBUG] Schemaless: Looking for field %#v in input field %#v" , translationValue , translationKey )
1509+ //log.Printf("[DEBUG] Schemaless: Looking for field %#v in input field %#v", translationValue, translationKey)
1510+
1511+ // Basic, default translator
1512+ if strings .Contains (val , "[" ) {
1513+ fields := []Valuereplace {
1514+ Valuereplace {
1515+ Value : val ,
1516+ },
1517+ }
1518+
1519+ fields = TranslateBadFieldFormats (fields , true )
1520+ if len (fields ) == 1 {
1521+ val = fields [0 ].Value
1522+ }
1523+ }
13511524
13521525 if strings .Contains (val , "." ) {
13531526 //if debug {
@@ -1381,6 +1554,11 @@ func runJsonTranslation(ctx context.Context, inputValue []byte, translation map[
13811554 log .Printf ("[ERROR] Schemaless: Error in RecurseFindKey for match %#v: %v" , match , err )
13821555 }
13831556
1557+ newOutput = strings .ReplaceAll (newOutput , match , recursed )
1558+ if strings .Contains (match , ".#" ) {
1559+ match = strings .ReplaceAll (match , ".#" , "[]" )
1560+ }
1561+
13841562 newOutput = strings .ReplaceAll (newOutput , match , recursed )
13851563 }
13861564
0 commit comments