Skip to content

Commit 31d0fdf

Browse files
committed
Added a JSON reverser to find where a string is inside two JSON blobs, and get reference locations
1 parent 0e222b0 commit 31d0fdf

File tree

2 files changed

+265
-1
lines changed

2 files changed

+265
-1
lines changed

reverse.go

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
package schemaless
2+
3+
/*
4+
Runs a reverse search through JSON, to find the schemaless based on two inputs
5+
*/
6+
7+
import (
8+
"log"
9+
"fmt"
10+
"strings"
11+
"reflect"
12+
"encoding/json"
13+
)
14+
15+
func FindMatchingString(stringToFind string, mapToSearch map[string]interface{}) string {
16+
for key, value := range mapToSearch {
17+
if _, ok := value.(string); !ok {
18+
continue
19+
}
20+
21+
foundValue := value.(string)
22+
if foundValue == stringToFind {
23+
return key
24+
}
25+
}
26+
27+
return ""
28+
}
29+
30+
// Recursive function to search for the schemaless in the map
31+
func ReverseTranslate(sourceMap, searchInMap map[string]interface{}) (string, error) {
32+
newMap := make(map[string]string)
33+
for key, _ := range searchInMap {
34+
newMap[key] = ""
35+
}
36+
37+
for key, value := range sourceMap {
38+
if _, ok := value.(string); !ok {
39+
// Check if it's a map and try to find the value in it
40+
if val, ok := value.(map[string]interface{}); ok {
41+
// Recursively search for the value in the map
42+
output, err := ReverseTranslate(val, searchInMap)
43+
if err != nil {
44+
log.Printf("[ERROR] Recursion failed on key %s: %v", key, err)
45+
continue
46+
}
47+
48+
outputMap := make(map[string]string)
49+
err = json.Unmarshal([]byte(output), &outputMap)
50+
if err != nil {
51+
log.Printf("[ERROR] Unmarshalling failed for outputmap: %v", err)
52+
continue
53+
}
54+
55+
for k, v := range outputMap {
56+
if v == "" {
57+
continue
58+
}
59+
60+
newMap[k] = key + "." + v
61+
}
62+
} else if val, ok := value.([]interface{}); ok {
63+
//log.Printf("List found: %#v", val)
64+
// Check if it's a list and try to find the value in it
65+
for i, v := range val {
66+
if stringval, ok := v.(string); ok {
67+
if stringval == "" {
68+
continue
69+
}
70+
71+
72+
matching := FindMatchingString(stringval, searchInMap)
73+
if len(matching) == 0 {
74+
//log.Printf("No matching found for %#v (2)", stringval)
75+
continue
76+
}
77+
78+
newMap[matching] = fmt.Sprintf("%s.#%d", key, i)
79+
80+
81+
} else if mapval, ok := v.(map[string]interface{}); ok {
82+
// Recursively search for the value in the map
83+
output, err := ReverseTranslate(mapval, searchInMap)
84+
if err != nil {
85+
log.Printf("[ERROR] Recursion failed on key %s: %v", key, err)
86+
continue
87+
}
88+
89+
outputMap := make(map[string]string)
90+
err = json.Unmarshal([]byte(output), &outputMap)
91+
if err != nil {
92+
log.Printf("[ERROR] Unmarshalling failed for outputmap: %v", err)
93+
continue
94+
}
95+
96+
for k, v := range outputMap {
97+
if v == "" {
98+
continue
99+
}
100+
101+
newMap[k] = fmt.Sprintf("%s.#%d.%s", key, i, v)
102+
}
103+
} else {
104+
log.Printf("No sublist handler for type %#v", reflect.TypeOf(v).String())
105+
}
106+
107+
//newMap[matching] = key + ".#" + string(i)
108+
}
109+
} else {
110+
log.Printf("No base handler for type %#v", reflect.TypeOf(value).String())
111+
}
112+
113+
continue
114+
}
115+
116+
matching := FindMatchingString(value.(string), searchInMap)
117+
if len(matching) == 0 {
118+
//log.Printf("No matching found for %#v", value)
119+
continue
120+
}
121+
122+
//log.Printf("[DEBUG] Matching for %#v: %s", value, matching)
123+
//newMap[key] = matching
124+
newMap[matching] = key
125+
}
126+
127+
reversed, err := json.MarshalIndent(newMap, "", " ")
128+
if err != nil {
129+
log.Printf("[ERROR] Marshalling failed: %v", err)
130+
return "", err
131+
}
132+
133+
return string(reversed), nil
134+
}
135+
136+
137+
138+
func removeWhitespace(input string) string {
139+
// Remove all whitespace from the strings
140+
return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(input, " ", ""), "\n", ""), "\t", "")
141+
}
142+
143+
func compareOutput(reversed, expectedOutput string) bool {
144+
// Remove all whitespace from the strings
145+
reversed = removeWhitespace(reversed)
146+
expectedOutput = removeWhitespace(expectedOutput)
147+
if reversed == expectedOutput {
148+
return true
149+
}
150+
151+
// Try to map to map and compare
152+
reversedMap := make(map[string]string)
153+
err := json.Unmarshal([]byte(reversed), &reversedMap)
154+
if err != nil {
155+
log.Printf("[ERROR] Unmarshalling failed for reversed: %v", err)
156+
return false
157+
}
158+
159+
expectedMap := make(map[string]string)
160+
err = json.Unmarshal([]byte(expectedOutput), &expectedMap)
161+
if err != nil {
162+
log.Printf("[ERROR] Unmarshalling failed for expected: %v", err)
163+
return false
164+
}
165+
166+
return reflect.DeepEqual(reversedMap, expectedMap)
167+
}
168+
169+
func ReverseTranslateStrings(findKeys, findInData string) (string, error) {
170+
var sourceMap map[string]interface{}
171+
err := json.Unmarshal([]byte(findKeys), &sourceMap)
172+
if err != nil {
173+
log.Printf("[ERROR] Unmarshalling to map[string]interface{} failed for sourceData: %v", err)
174+
return "", err
175+
}
176+
177+
var searchInMap map[string]interface{}
178+
err = json.Unmarshal([]byte(findInData), &searchInMap)
179+
if err != nil {
180+
log.Printf("[ERROR] Unmarshalling to map[string]interface{} failed for searchData: %v", err)
181+
return "", err
182+
}
183+
184+
return ReverseTranslate(sourceMap, searchInMap)
185+
186+
}
187+
188+
func runTest() {
189+
// Sample input data
190+
findKeys := `{
191+
"findme": "This is the value to find",
192+
"subkey": {
193+
"findAnother": "This is another value to find",
194+
"subsubkey": {
195+
"findAnother2": "Amazing subsubkey to find"
196+
},
197+
"sublist": [
198+
"This is a list",
199+
"This is a list",
200+
"Cool list item",
201+
"This is a list"
202+
],
203+
"objectlist": [{
204+
"key1": "This is a key"
205+
},
206+
{
207+
"key1": "Another cool thing"
208+
}]
209+
}
210+
}`
211+
212+
// Goal is to FIND the schemaless with key "findme" in the following data
213+
findInData := `{
214+
"key1": "This is the value to find",
215+
"key2": "This is another value to find",
216+
"key3": "Amazing subsubkey to find",
217+
"key4": "Cool list item",
218+
"key5": "Another cool thing"
219+
}`
220+
221+
// Expected output
222+
expectedOutput := `{
223+
"key1": "findme",
224+
"key2": "subkey.findAnother",
225+
"key3": "subkey.subsubkey.findAnother2",
226+
"key5": "subkey.objectlist.#1.key1",
227+
"key4": "subkey.sublist.#2"
228+
}`
229+
230+
reversed, err := ReverseTranslateStrings(findKeys, findInData)
231+
232+
/*
233+
var sourceMap map[string]interface{}
234+
err := json.Unmarshal([]byte(findKeys), &sourceMap)
235+
if err != nil {
236+
log.Printf("[ERROR] Unmarshalling failed: %v", err)
237+
return
238+
}
239+
240+
var searchInMap map[string]interface{}
241+
err = json.Unmarshal([]byte(findInData), &searchInMap)
242+
if err != nil {
243+
log.Printf("[ERROR] Unmarshalling failed: %v", err)
244+
return
245+
}
246+
247+
reversed, err := ReverseTranslate(sourceMap, searchInMap)
248+
*/
249+
250+
if err != nil {
251+
log.Printf("[ERROR] Reversing failed: %v", err)
252+
return
253+
}
254+
255+
sameKeyValues := compareOutput(reversed, expectedOutput)
256+
if !sameKeyValues {
257+
log.Printf("Failed")
258+
} else {
259+
log.Printf("Success")
260+
}
261+
}

translate.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package schemaless
2-
//package main
2+
3+
/*
4+
A package for translating from a JSON input to a standard format using OpenAI's GPT-4 API.
5+
*/
36

47
import (
58
"fmt"

0 commit comments

Comments
 (0)