{"id":13411545,"url":"https://github.com/InVisionApp/conjungo","last_synced_at":"2025-03-14T17:30:56.303Z","repository":{"id":57486493,"uuid":"77646849","full_name":"InVisionApp/conjungo","owner":"InVisionApp","description":"A small flexible merge library in go","archived":false,"fork":false,"pushed_at":"2023-05-08T18:30:43.000Z","size":122,"stargazers_count":125,"open_issues_count":10,"forks_count":18,"subscribers_count":108,"default_branch":"master","last_synced_at":"2024-07-31T20:47:59.247Z","etag":null,"topics":["go","golang","library","merge"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/InVisionApp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null}},"created_at":"2016-12-29T23:50:38.000Z","updated_at":"2024-04-24T18:27:47.000Z","dependencies_parsed_at":"2022-09-01T22:31:44.732Z","dependency_job_id":"52ba080c-ea7e-4f80-acea-4b77de8ee73f","html_url":"https://github.com/InVisionApp/conjungo","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/InVisionApp%2Fconjungo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/InVisionApp%2Fconjungo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/InVisionApp%2Fconjungo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/InVisionApp%2Fconjungo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/InVisionApp","download_url":"https://codeload.github.com/InVisionApp/conjungo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243551298,"owners_count":20309297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","library","merge"],"created_at":"2024-07-30T20:01:14.403Z","updated_at":"2025-03-14T17:30:56.285Z","avatar_url":"https://github.com/InVisionApp.png","language":"Go","readme":"| :warning: This project is no longer actively supported.\n| ---\n\n\u003cimg align=\"right\" src=\"images/gopher-merge.png\"\u003e\n\n# conjungo\n\n[![LICENSE](https://img.shields.io/badge/license-MIT-orange.svg)](LICENSE)\n[![Golang](https://img.shields.io/badge/Golang-v1.7-blue.svg)](https://golang.org/dl/)\n[![Godocs](https://img.shields.io/badge/golang-documentation-blue.svg)](https://godoc.org/github.com/InVisionApp/conjungo)\n[![Go Report Card](https://goreportcard.com/badge/github.com/InVisionApp/conjungo)](https://goreportcard.com/report/github.com/InVisionApp/conjungo)\n[![Travis Build Status](https://travis-ci.com/InVisionApp/conjungo.svg?token=KosA43m1X3ikri8JEukQ\u0026branch=master)](https://travis-ci.com/InVisionApp/conjungo) \n[![codecov](https://codecov.io/gh/InVisionApp/conjungo/branch/master/graph/badge.svg?token=lesB1PUEtL)](https://codecov.io/gh/InVisionApp/conjungo)\n\nA merge utility designed for flexibility and customizability. The library has a\nsingle simple point of entry that works out of the box for most basic use cases. \nFrom there, customizations can be made to the way two items are merged to fit \nyour specific needs.\n\nMerge any two things of the same type, including maps, slices, structs, and even \nbasic types like string and int. By default, the target value will be overwritten \nby the source. If the overwrite option is turned off, only new values in source \nthat do not already exist in target will be added.  \n\nIf you would like to change the way two items of a particular type get merged,\ncustom merge functions can be defined for any type or kind (see below).  \n\n## Why Conjungo?\n\nThe definition of Conjungo:  \n\u003e I.v. a., to bind together, connect, join, unite (very freq. in all perr. and species of composition); constr. with cum, inter se, the dat., or the acc. only; trop. also with ad.\n\nReference: [Latin Dictionary...](http://www.perseus.tufts.edu/hopper/text?doc=Perseus:text:1999.04.0059:entry=conjungo)\n\nThere are other merge libraries written in go, but none of them have the \nflexibility of this one. If you simply need to merge two things, a default \nset of merge functions are defined for merging maps, slices, and structs like \nmost other libraries. But, if the way these default functions are defined does \nnot meet your needs, Conjungo provides the ability to define your own merge \nfunctions. For instance, the default behavior when merging two integers is to \nreplace the target with the source, but if you'd like to redefine that, you \ncan write a custom merge function that is used when assessing integers. A custom \nfunction could add the two integers and return the result, or return the larger \nof the two integers. You could define a custom merge function for a specific struct \ntype in your code, and define how that gets merged. The customizability of how \nthings get merged is the focus of Conjungo. \n\nThe need for this library arose when we were merging large custom structs. We \nfound that there was no single library that merged all the parts of the struct \nin the way that we needed. We had struct fields that were pointers to sub structs \nand maps that needed to be followed instead of simply replaced. We had slices \nthat needed to be appended but also deduped. Conjungo solves these types of \nproblems by allowing custom functions to be defined to handle each type.\n\n## Setup\nTo get **conjungo**:\n```sh\ngo get github.com/InVisionApp/conjungo\n```\n\nWe recommend that you vendor it within your project. We chose to use govendor.\n\n```sh \ngovendor fetch github.com/InVisionApp/conjungo\n```\n\n## Usage\n### Simple Merge\nMerge two structs together:\n```go\ntype Foo struct {\n\tName    string\n\tSize    int\n\tSpecial bool\n\tSubMap  map[string]string\n}\n\ntargetStruct := Foo{\n\tName:    \"target\",\n\tSize:    2,\n\tSpecial: false,\n\tSubMap:  map[string]string{\"foo\": \"unchanged\", \"bar\": \"orig\"},\n}\n\nsourceStruct := Foo{\n\tName:    \"source\",\n\tSize:    4,\n\tSpecial: true,\n\tSubMap:  map[string]string{\"bar\": \"newVal\", \"safe\": \"added\"},\n}\n\nerr := conjungo.Merge(\u0026targetStruct, sourceStruct, nil)\nif err != nil {\n\tlog.Error(err)\n}\n```\nresults in:\n```json\n{\n  \"Name\": \"source\",\n  \"Size\": 4,\n  \"Special\": true,\n  \"SubMap\": {\n    \"bar\": \"newVal\",\n    \"foo\": \"unchanged\",\n    \"safe\": \"added\"\n  }\n}\n```\n\n### Options\n**Overwrite** `bool`  \nIf true, overwrite a target value with source value even if it already exists\n\n**ErrorOnUnexported** `bool`  \nUnexported fields on a struct can not be set. When a struct contains an unexported\nfield, the default behavior is to treat the entire struct as a single entity and\nreplace according to Overwrite settings.  \nIf this is enabled, an error will be thrown instead.\n\n### Custom Merge Functions\n#### Define a custom merge function for a type:\n```go\nopts := conjungo.NewOptions()\nopts.MergeFuncs.SetTypeMergeFunc(\n\treflect.TypeOf(0),\n\t// merge two 'int' types by adding them together\n\tfunc(t, s reflect.Value, o *conjungo.Options) (reflect.Value, error) {\n\t\tiT, _ := t.Interface().(int)\n\t\tiS, _ := s.Interface().(int)\n\t\treturn reflect.ValueOf(iT + iS), nil\n\t},\n)\n\nx := 1\ny := 2\n\nerr := conjungo.Merge(\u0026x, y, opts)\nif err != nil {\n\tlog.Error(err)\n}\n\n// x == 3\n```\n\n#### Define a custom merge function for a kind:\n```go\nopts := conjungo.NewOptions()\nopts.MergeFuncs.SetKindMergeFunc(\n\treflect.TypeOf(struct{}{}).Kind(),\n\t// merge two 'struct' kinds by replacing the target with the source\n\t// provides a mechanism to set override = true for just structs\n\tfunc(t, s reflect.Value, o *conjungo.Options) (reflect.Value, error) {\n\t\treturn s, nil\n\t},\n)\n```\n\n#### Define a custom merge function for a struct type:\n```go\n\ttype Foo struct {\n\t\tName string\n\t\tSize int\n\t}\n\n\ttarget := Foo{\n\t\tName: \"bar\",\n\t\tSize: 25,\n\t}\n\n\tsource := Foo{\n\t\tName: \"baz\",\n\t\tSize: 35,\n\t}\n\n\topts := conjungo.NewOptions()\n\topts.MergeFuncs.SetTypeMergeFunc(\n\t\treflect.TypeOf(Foo{}),\n\t\t// merge two 'int' types by adding them together\n\t\tfunc(t, s reflect.Value, o *conjungo.Options) (reflect.Value, error) {\n\t\t\ttFoo := t.Interface().(Foo)\n\t\t\tsFoo := s.Interface().(Foo)\n\n\t\t\t// names are merged by concatenating them\n\t\t\ttFoo.Name = tFoo.Name + \".\" + sFoo.Name\n\t\t\t// sizes are merged by averaging them\n\t\t\ttFoo.Size = (tFoo.Size + sFoo.Size) / 2\n\n\t\t\treturn reflect.ValueOf(tFoo), nil\n\t\t},\n\t)\n```\n\n#### Define a custom type and a function to merge it:\n```go\ntype jsonString string\n\nvar targetJSON jsonString = `\n{\n  \"a\": \"wrong\",\n  \"b\": 1,\n  \"c\": {\"bar\": \"orig\", \"foo\": \"unchanged\"},\n}`\n\nvar sourceJSON jsonString = `\n{\n  \"a\": \"correct\",\n  \"b\": 2,\n  \"c\": {\"bar\": \"newVal\", \"safe\": \"added\"},\n}`\n\nopts := conjungo.NewOptions()\nopts.MergeFuncs.SetTypeMergeFunc(\n\treflect.TypeOf(jsonString(\"\")),\n\t// merge two json strings by unmarshalling them to maps\n\tfunc(t, s reflect.Value, o *conjungo.Options) (reflect.Value, error) {\n\t\ttargetStr, _ := t.Interface().(jsonString)\n\t\tsourceStr, _ := s.Interface().(jsonString)\n\n\t\ttargetMap := map[string]interface{}{}\n\t\tif err := json.Unmarshal([]byte(targetStr), \u0026targetMap); err != nil {\n\t\t\treturn reflect.Value{}, err\n\t\t}\n\n\t\tsourceMap := map[string]interface{}{}\n\t\tif err := json.Unmarshal([]byte(sourceStr), \u0026sourceMap); err != nil {\n\t\t\treturn reflect.Value{}, err\n\t\t}\n\n\t\terr := conjungo.Merge(\u0026targetMap, sourceMap, o)\n\t\tif err != nil {\n\t\t\treturn reflect.Value{}, err\n\t\t}\n\n\t\tmergedJSON, err := json.Marshal(targetMap)\n\t\tif err != nil {\n\t\t\treturn reflect.Value{}, err\n\t\t}\n\n\t\treturn reflect.ValueOf(jsonString(mergedJSON)), nil\n\t},\n)\n```\n\nSee [working examples](_example/main.go) for more details.\n","funding_links":[],"categories":["数据结构与算法","Data Structures and Algorithms","Data Structures","数据结构","数据结构`go语言实现的数据结构与算法`","Uncategorized","Generators"],"sub_categories":["杂项数据结构和算法","Miscellaneous Data Structures and Algorithms","Advanced Console UIs","Standard CLI","标准 CLI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FInVisionApp%2Fconjungo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FInVisionApp%2Fconjungo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FInVisionApp%2Fconjungo/lists"}