【发布时间】:2018-05-29 08:25:27
【问题描述】:
编辑:添加问题上下文
我正在为 ArangoDB 数据库制作迁移工具。不知道那是什么?结帐https://www.arangodb.com。现在像大多数迁移工具一样,我的需要创建集合,在逻辑上相当于 SQL 表。它需要创建或删除索引、集合、图表和其他 DB 实体,以及执行任意 AQL(ArangoDB 的类似 SQL 的代数)。
为了支持这一点,用户创建了一系列迁移文件,每个文件都说明了如何处理该步骤。所以步骤 1 可能会说“创建集合用户”,步骤 67 可能会说“删除集合用户——因为我们重命名了它”。我想使用 YAML,因为 ArangoDB 团队明确问我为什么不使用 YAML。由于二进制发行版不需要 Java,Golang 似乎比我现有的 Java 实现更好。
话虽如此,我有几种不同类型的结构存储在不同的 yaml 文件中。我可以通过读取 yaml 的第一行来判断哪个结构在哪个文件中。我希望在阅读文件时尽可能保持干燥。
我试图有一个工厂方法,可以从这段代码中的文件创建正确的结构。我们可以假设所有的 pickT 实例都会返回一个有效的 Migration 接口实现。
func pickT(contents []byte) (Migration, error) {
s := string(contents)
switch {
case collection.MatchString(s):
return new(Collection), nil
default:
return nil, errors.New("Can't determine YAML type")
}
}
func toStruct(childPath string) Migration {
contents := open(childPath)
t, err := pickT(contents)
if err != nil {
log.Fatal(err)
}
//c := Collection{}
err = yaml.UnmarshalStrict(contents, &t)
if err != nil {
log.Fatal(err)
}
return t
}
此代码不起作用。 Yaml 踢出下面的错误。
--- FAIL: TestLoadFromPath (0.00s)
panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type main.Migration [recovered]
panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type main.Migration [recovered]
panic: reflect.Set: value of type map[interface {}]interface {} is not assignable to type main.Migration
goroutine 5 [running]:
testing.tRunner.func1(0xc4201060f0)
/usr/local/go/src/testing/testing.go:711 +0x2d2
panic(0x68ade0, 0xc420010cf0)
/usr/local/go/src/runtime/panic.go:491 +0x283
gopkg.in/yaml%2ev2.handleErr(0xc420057b18)
/home/jdavenpo/go/src/gopkg.in/yaml.v2/yaml.go:164 +0x9f
panic(0x68ade0, 0xc420010cf0)
/usr/local/go/src/runtime/panic.go:491 +0x283
reflect.Value.assignTo(0x69e740, 0xc42007d230, 0x15, 0x6f30e4, 0xb, 0x6a45a0, 0xc420010cd0, 0x69e740, 0xc42007d230, 0x15)
/usr/local/go/src/reflect/value.go:2192 +0x3a6
reflect.Value.Set(0x6a45a0, 0xc420010cd0, 0x194, 0x69e740, 0xc42007d230, 0x15)
/usr/local/go/src/reflect/value.go:1357 +0xa4
gopkg.in/yaml%2ev2.(*decoder).mapping(0xc420060900, 0xc4200644e0, 0x6a45a0, 0xc420010cd0, 0x194, 0x6a45a0)
/home/jdavenpo/go/src/gopkg.in/yaml.v2/decode.go:522 +0x8e2
gopkg.in/yaml%2ev2.(*decoder).unmarshal(0xc420060900, 0xc4200644e0, 0x6a45a0, 0xc420010cd0, 0x194, 0xc4200644e0)
/home/jdavenpo/go/src/gopkg.in/yaml.v2/decode.go:292 +0x136
gopkg.in/yaml%2ev2.(*decoder).document(0xc420060900, 0xc420064480, 0x6a45a0, 0xc420010cd0, 0x194, 0xc4200608c0)
/home/jdavenpo/go/src/gopkg.in/yaml.v2/decode.go:304 +0x80
gopkg.in/yaml%2ev2.(*decoder).unmarshal(0xc420060900, 0xc420064480, 0x6a45a0, 0xc420010cd0, 0x194, 0x194)
/home/jdavenpo/go/src/gopkg.in/yaml.v2/decode.go:280 +0x1d2
gopkg.in/yaml%2ev2.unmarshal(0xc42010c000, 0x3b, 0x23b, 0x67c4a0, 0xc420010cd0, 0x1, 0x0, 0x0)
/home/jdavenpo/go/src/gopkg.in/yaml.v2/yaml.go:101 +0x289
gopkg.in/yaml%2ev2.UnmarshalStrict(0xc42010c000, 0x3b, 0x23b, 0x67c4a0, 0xc420010cd0, 0x0, 0x0)
/home/jdavenpo/go/src/gopkg.in/yaml.v2/yaml.go:87 +0x58
github.com/deusdat/arangomigo.toStruct(0xc420014360, 0x26, 0x0, 0x0)
/home/jdavenpo/go/src/github.com/deusdat/arangomigo/migrations.go:102 +0x295
github.com/deusdat/arangomigo.loadFrom(0x6f8059, 0x1a, 0x0, 0x0, 0x0)
/home/jdavenpo/go/src/github.com/deusdat/arangomigo/migrations.go:67 +0x4d6
github.com/deusdat/arangomigo.TestLoadFromPath(0xc4201060f0)
/home/jdavenpo/go/src/github.com/deusdat/arangomigo/migrations_test.go:11 +0x48
testing.tRunner(0xc4201060f0, 0x705950)
/usr/local/go/src/testing/testing.go:746 +0xd0
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:789 +0x2de
据我所知,Go 类型会擦除界面,至少在功能上是这样。有什么方法可以动态选择类型,然后让 Yaml 将其转换出来?我知道我可以通过在不同的功能中一遍又一遍地重复相同的逻辑来手动执行此操作,例如下面的功能,但这似乎......很糟糕。
func fromCollectionYaml(content string) Migration {
c := Collection{}
err := yaml.Unmarshal(content, &c)
if err != nil {
log.Fatal(err)
}
return c
}
编辑:添加 Collection 结构和 Yaml
type: collection
Action: create
Name: Users
Journalsize: 10
type Collection struct {
Name string
Action Action
ShardKeys []string
JournalSize int
NumberOfShards int
WaitForSync bool
AllowUserKeys bool
Volatile bool
Compactable bool
}
func (this Collection) migrate(action Action, db *arangolite.Database) error {
return nil
}
在不久的将来,我需要为索引添加结构。图表和其他 ArangoDB 相关功能。每个 Yaml 文件都需要进入一个生成和迁移的结构,它只是一个接口的实例,具有当前与结构一起显示的一个函数。
【问题讨论】:
-
能否附上集合结构和yaml文件示例?