First init
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..92a0861
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,21 @@
+module github.com/KorAP/KoralPipe-TermMapper
+
+go 1.22.2
+
+require (
+ github.com/rs/zerolog v1.34.0
+ github.com/stretchr/testify v1.10.0
+ github.com/tidwall/gjson v1.18.0
+ github.com/tidwall/sjson v1.2.5
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.0 // indirect
+ golang.org/x/sys v0.12.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..9abbe28
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,34 @@
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
+github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
+github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
+github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
+github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/termmapper.go b/termmapper.go
new file mode 100644
index 0000000..b2d41fe
--- /dev/null
+++ b/termmapper.go
@@ -0,0 +1,454 @@
+package termmapper
+
+/*
+$( => PUNCT PunctType=Brck ``, '', *RRB*, *LRB*, -
+$, => PUNCT PunctType=Comm ,
+$. => PUNCT PunctType=Peri ., :, ?, ;, !
+ADJA => ADJ _ neuen, neue, deutschen, ersten, anderen
+ADJD => ADJ Variant=Short gut, rund, knapp, deutlich, möglich
+ADV => ADV _ auch, nur, noch, so, aber
+APPO => ADP AdpType=Post zufolge, nach, gegenüber, wegen, über
+APPR => ADP AdpType=Prep in, von, mit, für, auf
+APPRART => ADP AdpType=Prep|PronType=Art im, am, zum, zur, vom
+APZR => ADP AdpType=Circ an, hinaus, aus, her, heraus
+ART => DET PronType=Art der, die, den, des, das
+CARD => NUM NumType=Card 000, zwei, drei, vier, fünf
+FM => X Foreign=Yes New, of, de, Times, the
+ITJ => INTJ _ naja, Ach, äh, Na, piep
+KOKOM => CCONJ ConjType=Comp als, wie, denn, wir
+KON => CCONJ _ und, oder, sondern, sowie, aber
+KOUI => SCONJ _ um, ohne, statt, anstatt, Ums
+KOUS => SCONJ _ daß, wenn, weil, ob, als
+NE => PROPN _ SPD, Deutschland, USA, dpa, Bonn
+NN => NOUN _ Prozent, Mark, Millionen, November, Jahren
+PAV => ADV PronType=Dem
+PDAT => DET PronType=Dem dieser, diese, diesem, dieses, diesen
+PDS => PRON PronType=Dem das, dies, die, diese, der
+PIAT => DET PronType=Ind,Neg,Tot keine, mehr, alle, kein, beiden
+PIDAT => DET AdjType=Pdt|PronType=Ind,Neg,Tot
+PIS => PRON PronType=Ind,Neg,Tot man, allem, nichts, alles, mehr
+PPER => PRON PronType=Prs es, sie, er, wir, ich
+PPOSAT => DET Poss=Yes|PronType=Prs ihre, seine, seiner, ihrer, ihren
+PPOSS => PRON Poss=Yes|PronType=Prs ihren, Seinen, seinem, unsrigen, meiner
+PRELAT => DET PronType=Rel deren, dessen, die
+PRELS => PRON PronType=Rel die, der, das, dem, denen
+PRF => PRON PronType=Prs|Reflex=Yes sich, uns, mich, mir, dich
+PTKA => PART _ zu, am, allzu, Um
+PTKANT => PART PartType=Res nein, ja, bitte, Gewiß, Also
+PTKNEG => PART Polarity=Neg nicht
+PTKVZ => ADP PartType=Vbp an, aus, ab, vor, auf
+PTKZU => PART PartType=Inf zu, zur, zum
+PWAT => DET PronType=Int welche, welchen, welcher, wie, welchem
+PWAV => ADV PronType=Int wie, wo, warum, wobei, wonach
+PWS => PRON PronType=Int was, wer, wem, wen, welches
+TRUNC => X Hyph=Yes Staats-, Industrie-, Finanz-, Öl-, Lohn-
+VAFIN => AUX Mood=Ind|VerbForm=Fin ist, hat, wird, sind, sei
+VAIMP => AUX Mood=Imp|VerbForm=Fin Seid, werde, Sei
+VAINF => AUX VerbForm=Inf werden, sein, haben, worden, Dabeisein
+VAPP => AUX Aspect=Perf|VerbForm=Part worden, gewesen, geworden, gehabt, werden
+VMFIN => VERB Mood=Ind|VerbForm=Fin|VerbType=Mod kann, soll, will, muß, sollen
+VMINF => VERB VerbForm=Inf|VerbType=Mod können, müssen, wollen, dürfen, sollen
+VMPP => VERB Aspect=Perf|VerbForm=Part|VerbType=Mod gewollt
+VVFIN => VERB Mood=Ind|VerbForm=Fin sagte, gibt, geht, steht, kommt
+VVIMP => VERB Mood=Imp|VerbForm=Fin siehe, sprich, schauen, Sagen, gestehe
+VVINF => VERB VerbForm=Inf machen, lassen, bleiben, geben, bringen
+VVIZU => VERB VerbForm=Inf einzusetzen, durchzusetzen, aufzunehmen, abzubauen, umzusetzen
+VVPP => VERB Aspect=Perf|VerbForm=Part gemacht, getötet, gefordert, gegeben, gestellt
+XY => X _ dpa, ap, afp, rtr, wb
+*/
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/rs/zerolog/log"
+ "github.com/tidwall/gjson"
+ "github.com/tidwall/sjson"
+)
+
+/*
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "strings"
+)
+
+var mapping = map[string]string{
+ "$(":"PUNCT",
+}
+
+// Recursive function to turn the UPos query into a STTS query
+func koralRewriteUpos2Stts(koralquery interface{}) interface{} {
+ switch v := koralquery.(type) {
+ case map[string]interface{}:
+ // Check for '@type' key and act accordingly
+ if typ, ok := v["@type"].(string); ok {
+ switch typ {
+ case "koral:term":
+
+ // Modify the key to use STTS
+// This may require to turn object into a koral:token with terms like:
+
+
+ if key, ok := v["key"].(string); ok {
+ v["key"] = "hallo-" + key
+ }
+ case "operation":
+ // Handle the 'operators' key by recursively modifying each operator
+ if operators, ok := v["operators"].([]interface{}); ok {
+ for i, operator := range operators {
+ operators[i] = modifyJSON(operator)
+ }
+ v["operators"] = operators
+ }
+ }
+ }
+ // Recursively modify any nested maps
+ for k, val := range v {
+ v[k] = modifyJSON(val)
+ }
+ return v
+ case []interface{}:
+ // Recursively modify elements of arrays
+ for i, item := range v {
+ v[i] = modifyJSON(item)
+ }
+ return v
+ }
+ return koralquery
+}
+
+func main() {
+ // Sample JSON input string
+ jsonStr := `{
+ "@type": "operation",
+ "operators": [
+ {
+ "@type": "term",
+ "key": "example1"
+ },
+ {
+ "@type": "term",
+ "key": "example2"
+ },
+ {
+ "@type": "operation",
+ "operators": [
+ {
+ "@type": "term",
+ "key": "nested"
+ }
+ ]
+ }
+ ]
+ }`
+
+ // Parse the JSON string into a generic interface{}
+ var data interface{}
+ err := json.Unmarshal([]byte(jsonStr), &data)
+ if err != nil {
+ log.Fatal("Error unmarshaling JSON:", err)
+ }
+
+ // Modify the JSON structure recursively
+ modifiedData := modifyJSON(data)
+
+ // Marshal the modified data back into a JSON string
+ modifiedJSON, err := json.MarshalIndent(modifiedData, "", " ")
+ if err != nil {
+ log.Fatal("Error marshaling JSON:", err)
+ }
+
+ // Output the modified JSON string
+ fmt.Println(string(modifiedJSON))
+}
+
+
+
+func turnupostostts(json string, targetFoundry string, targetLayer string) {
+ if targetLayer == "" {
+ targetLayer = "p"
+ }
+
+ ldType := "@type"
+
+ if ldType == "koral:span" {
+ next
+ }
+ if ldType == "koral:term" {
+ if foundry == if layer === key -> rewrite
+ }
+
+ // Iterate through the query and whenever a term is requested without a foundry, and without a layser or layer p,
+ // change the key following the mapping
+
+
+}
+
+func addupostooutput(json string, reffoundry string, foundry string) {
+ // https://universaldependencies.org/tagset-conversion/de-stts-uposf.html
+ // Iterate through all matches and add to all xml snippets a line of foundry
+
+}
+
+*/
+
+func Hui() string {
+ return "test"
+}
+
+func Map2(json []byte) string {
+ /*
+ result := gjson.GetBytes(json, "query")
+ var raw []byte
+ if result.Index > 0 {
+ raw = json[result.Index:result.Index+len(result.Raw)]
+ } else {
+ raw = []byte(result.Raw)
+ }
+
+ if result.IsObject() {
+ koralType := gjson.GetBytes(raw, "@type").String()
+ switch koralType {
+ case "koral:term":
+
+ }
+ }
+ */
+
+ koralObj := gjson.ParseBytes(json)
+
+ switch koralObj.Get("@type").String() {
+ case "koral:term":
+ {
+ if koralObj.Get("value").String() == "KOKOM" {
+ // TODO: Turn this in a token, if it isn't already!
+ newJson, _ := sjson.Set(string(json), "value", "CCONJ")
+ return newJson
+ }
+ }
+
+ case "koral:operation":
+ {
+
+ }
+
+ }
+ /*
+
+ var raw []byte
+ if result.Index > 0 {
+ raw = json[result.Index:result.Index+len(result.Raw)]
+ } else {
+ raw = []byte(result.Raw)
+ }
+ */
+ return "jj"
+}
+
+// token writes a token to the string builder
+func token(strBuilder *strings.Builder, foundry string, layer string, keys []string) {
+ strBuilder.WriteString(`{"@type":"koral:token","wrap":`)
+ if len(keys) > 1 {
+ termGroup(strBuilder, foundry, layer, keys)
+ } else {
+ term(strBuilder, foundry, layer, keys[0], true)
+ }
+ strBuilder.WriteString(`}`)
+}
+
+// termGroup writes a termGroup to the string builder
+func termGroup(strBuilder *strings.Builder, foundry string, layer string, keys []string) {
+ strBuilder.WriteString(`{"@type":"koral:termGroup","relation":"relation:and","operation":"operation:and","operands":[`)
+ for i, key := range keys {
+ term(strBuilder, foundry, layer, key, true) // temporary
+ if i < len(keys)-1 {
+ strBuilder.WriteString(",")
+ }
+ }
+ strBuilder.WriteString(`]}`)
+}
+
+// term writes a term to the string builder
+func term(strBuilder *strings.Builder, foundry string, layer string, key string, match bool) {
+
+ // TODO: May have ne!!!!
+ strBuilder.WriteString(`{"@type":"koral:term","match":"match:`)
+ if match {
+ strBuilder.WriteString("eq")
+ } else {
+ strBuilder.WriteString("ne")
+ }
+ strBuilder.WriteString(`","foundry":"`)
+ strBuilder.WriteString(foundry)
+ strBuilder.WriteString(`","layer":"`)
+ strBuilder.WriteString(layer)
+ strBuilder.WriteString(`","key":"`)
+ strBuilder.WriteString(key)
+ strBuilder.WriteString(`"}`)
+}
+
+func flatten() {
+
+ // if a termGroup isan operand in a termGroup with the same relation/operation:
+ // flatten the termGroup into the parent termGroup
+
+ // if a termGroup has only a single term, remove the group
+}
+
+func replaceWrappedTerm(jsonString string, foundry string, layer string, key string) string {
+ var err error
+ jsonString, err = sjson.Set(jsonString, "foundry", foundry)
+ if err != nil {
+ log.Error().Err(err).Msg("Error setting foundry")
+ }
+ jsonString, err = sjson.Set(jsonString, "layer", layer)
+ if err != nil {
+ log.Error().Err(err).Msg("Error setting layer")
+ }
+ jsonString, err = sjson.Set(jsonString, "key", key)
+ if err != nil {
+ log.Error().Err(err).Msg("Error setting key")
+ }
+ return jsonString
+}
+
+func replaceGroupedTerm(jsonString string, op []int, foundry string, layer string, key string) string {
+ var err error
+
+ strInt := "operands." + strconv.Itoa(op[0]) + "."
+ jsonString, err = sjson.Set(jsonString, strInt+"foundry", foundry)
+ if err != nil {
+ log.Error().Err(err).Msg("Error setting foundry")
+ }
+ jsonString, err = sjson.Set(jsonString, strInt+"layer", layer)
+ if err != nil {
+ log.Error().Err(err).Msg("Error setting layer")
+ }
+ jsonString, err = sjson.Set(jsonString, strInt+"key", key)
+ if err != nil {
+ log.Error().Err(err).Msg("Error setting key")
+ }
+
+ if len(op) > 1 {
+ for i := 1; i < len(op); i++ {
+ jsonString, err = sjson.Delete(jsonString, "operands."+strconv.Itoa(op[i]))
+ if err != nil {
+ log.Error().Err(err).Msg("Error deleting operand")
+ }
+ }
+ }
+
+ return jsonString
+}
+
+/*
+func replaceTermWithToken(jsonString string) string {
+ // Replace the term with the token
+ replacedString, err := sjson.Set(jsonString, "wrap.operands.0", token())
+ if err != nil {
+ return jsonString // Return the original string in case of an error
+ }
+ return replacedString
+
+// case1: 1 -> 1 the term is an operand in a termGroup with the same relation/operation
+// case2: 1 -> 1 the term is wrapped
+// case3: 1 -> 1 the term is an operand in a termGroup with a different relation/operation
+// case4: n -> 1 the term is an operand in a termGroup with the same relation/operation
+// case5: n -> 1 the term is wrapped
+// case6: n -> 1 the term is an operand in a termGroup with a different relation/operation
+// case7: 1 -> n the term is an operand in a termGroup with the same relation/operation
+// case8: 1 -> n the term is wrapped
+// case9: 1 -> n the term is an operand in a termGroup with a different relation/operation
+ }
+*/
+
+func Map(jsonStr string) string {
+
+ obj := gjson.Get(jsonStr, "query")
+
+ // value := gjson.Get(json, "name.last")
+
+ /*
+
+ // Modify the JSON structure recursively
+ modifiedData := modifyJSON(ast.NewAny(data))
+
+ // Marshal the modified data back into a JSON string
+ modifiedJSON, err := sonic.MarshalString(modifiedData)
+
+ // Parse the JSON string into a generic interface{}
+ var data interface{}
+
+ err := sonic.UnmarshalString(jsonStr, data)
+
+ if err != nil {
+ log.Fatal("Error unmarshaling JSON:", err)
+ return ""
+ }
+
+
+
+ if err != nil {
+ log.Fatal("Error marshaling JSON:", err)
+ }
+ */
+ // Output the modified JSON string
+ return obj.String() //modifyJSON(obj)
+}
+
+// Recursive function to modify JSON using Sonic library
+//func modifyJSON(data gjson.Result) string {
+
+// Check if data is a map
+// if data.IsObject() {
+/*
+ dataMap := data.Map()
+
+ koralType := dataMap["@type"].String()
+
+ // Look for @type key
+
+ switch koralType {
+ case "koral:term":
+ // Modify the key by adding 'hallo-' prefix
+
+ // sjson.SetRaw(data.String())
+ sjson.Set(data.Path(data.Bytes()), "key", "hallo-"+dataMap["key"].String())
+
+ dataMap["key"] = "hallo-" + dataMap["key"].String()
+ /*
+ if key, found := data.GetString("key"); found {
+ data.Set("key", "hallo-"+key)
+ }
+*/
+/*
+ case "koral:operation":
+ // Handle the 'operators' key by recursively modifying each operator
+ if operators, found := data.GetArray("operators"); found {
+ for i := range operators {
+ operators[i] = modifyJSON(operators[i])
+ }
+ data.Set("operators", operators)
+ }
+ }*/
+/*
+ // Recursively modify any nested objects
+ data.ForEach(func(k string, v sonic.Any) {
+ data.Set(k, modifyJSON(v))
+ })
+*/
+//}
+// Handle arrays by modifying elements recursively
+/*
+ if data.IsArray() {
+ for i := range data.GetArray() {
+ data.Set(i, modifyJSON(data.GetArray()[i]))
+ }
+ }
+*/
+/*
+ return data
+}
+*/
diff --git a/termmapper_test.go b/termmapper_test.go
new file mode 100644
index 0000000..0492c35
--- /dev/null
+++ b/termmapper_test.go
@@ -0,0 +1,106 @@
+package termmapper
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestConstants(t *testing.T) {
+ assert := assert.New(t)
+ assert.Equal(Hui(), "test")
+}
+
+// KoralPipe-TermMapping
+
+func TestTokenBuilder(t *testing.T) {
+
+ assert := assert.New(t)
+
+ var strBuilder strings.Builder
+ term(&strBuilder, "myfoundry", "mylayer", "mykey1", true)
+ assert.Equal(strBuilder.String(), `{"@type":"koral:term","match":"match:eq","foundry":"myfoundry","layer":"mylayer","key":"mykey1"}`)
+ strBuilder.Reset()
+
+ token(&strBuilder, "myfoundry", "mylayer", []string{"mykey1", "mykey2"})
+ assert.Equal(strBuilder.String(), "{\"@type\":\"koral:token\",\"wrap\":{\"@type\":\"koral:termGroup\",\"relation\":\"relation:and\",\"operation\":\"operation:and\",\"operands\":[{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey1\"},{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey2\"}]}}")
+ strBuilder.Reset()
+
+ token(&strBuilder, "myfoundry", "mylayer", []string{"mykey2"})
+ assert.Equal(strBuilder.String(), "{\"@type\":\"koral:token\",\"wrap\":{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey2\"}}")
+ strBuilder.Reset()
+}
+
+/*
+ jsonStr := `{
+ "query": {
+ "@type": "koral:operation",
+ "operators": [
+ {
+ "@type": "koral:term",
+ "key": "example1"
+ },
+ {
+ "@type": "koral:term",
+ "key": "example2"
+ },
+ {
+ "@type": "koral:operation",
+ "operators": [
+ {
+ "@type": "koral:term",
+ "key": "nested"
+ }
+ ]
+ }
+ ]
+ }
+ }`
+*/
+
+func TestTermReplacement(t *testing.T) {
+
+ assert := assert.New(t)
+
+ // case1: 1 -> 1 the term is wrapped
+ testStr := replaceWrappedTerm("{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey\"}", "myfoundry2", "mylayer2", "mykey2")
+ assert.Equal(testStr, "{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry2\",\"layer\":\"mylayer2\",\"key\":\"mykey2\"}")
+
+ // case2: 1 -> 1 the term is an operand in a termGroup with the same relation/operation
+ // case3: 1 -> 1 the term is an operand in a termGroup with a different relation/operation
+ testStr = replaceGroupedTerm(
+ "{\"@type\":\"koral:termGroup\",\"relation\":\"relation:and\",\"operation\":\"operation:and\",\"operands\":[{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey\"},{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey2\"}]}",
+ []int{0},
+ "myfoundryX",
+ "mylayerX",
+ "mykeyX",
+ )
+ assert.Equal(testStr, "{\"@type\":\"koral:termGroup\",\"relation\":\"relation:and\",\"operation\":\"operation:and\",\"operands\":[{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundryX\",\"layer\":\"mylayerX\",\"key\":\"mykeyX\"},{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey2\"}]}")
+
+ testStr = replaceGroupedTerm(
+ "{\"@type\":\"koral:termGroup\",\"relation\":\"relation:and\",\"operation\":\"operation:and\",\"operands\":[{\"@type\":\"koral:term\",\"match\":\"match:ne\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey\"},{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey2\"}]}",
+ []int{0},
+ "myfoundryX",
+ "mylayerX",
+ "mykeyX",
+ )
+ assert.Equal(testStr, "{\"@type\":\"koral:termGroup\",\"relation\":\"relation:and\",\"operation\":\"operation:and\",\"operands\":[{\"@type\":\"koral:term\",\"match\":\"match:ne\",\"foundry\":\"myfoundryX\",\"layer\":\"mylayerX\",\"key\":\"mykeyX\"},{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey2\"}]}")
+
+ // case4: n -> 1 the term is an operand in a termGroup with the same relation/operation
+ testStr = replaceGroupedTerm(
+ "{\"@type\":\"koral:termGroup\",\"relation\":\"relation:and\",\"operation\":\"operation:and\",\"operands\":[{\"@type\":\"koral:term\",\"match\":\"match:ne\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey\"},{\"@type\":\"koral:term\",\"match\":\"match:eq\",\"foundry\":\"myfoundry\",\"layer\":\"mylayer\",\"key\":\"mykey2\"}]}",
+ []int{0, 1},
+ "myfoundryX",
+ "mylayerX",
+ "mykeyX",
+ )
+ assert.Equal(testStr, "{\"@type\":\"koral:termGroup\",\"relation\":\"relation:and\",\"operation\":\"operation:and\",\"operands\":[{\"@type\":\"koral:term\",\"match\":\"match:ne\",\"foundry\":\"myfoundryX\",\"layer\":\"mylayerX\",\"key\":\"mykeyX\"}]}")
+
+ // case5: n -> 1 the term is an operand in a termGroup with a different relation/operation
+ // case6: 1 -> n the term is wrapped
+ // case7: 1 -> n the term is an operand in a termGroup with the same relation/operation
+ // case8: 1 -> n the term is an operand in a termGroup with a different relation/operation
+ // case9: n -> n the term is an operand in a termGroup with the same relation/operation
+ // case10: n -> n the term is an operand in a termGroup with a different relation/operation
+}