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
+}