/
dbToDb.go
162 lines (134 loc) · 4.93 KB
/
dbToDb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright (c) 2016 OpenM++
// This code is licensed under the MIT license (see LICENSE.txt for details)
package main
import (
"database/sql"
"errors"
"github.com/openmpp/go/ompp/config"
"github.com/openmpp/go/ompp/db"
)
// copy model from source database to destination database
func dbToDb(modelName string, modelDigest string, runOpts *config.RunOptions) error {
// validate source and destination
inpConnStr := runOpts.String(dbConnStrArgKey)
inpDriver := runOpts.String(dbDriverArgKey)
outConnStr := runOpts.String(toDbConnStrArgKey)
outDriver := runOpts.String(toDbDriverArgKey)
if inpConnStr == outConnStr && inpDriver == outDriver {
return errors.New("source same as destination: cannot overwrite model in database")
}
// open source database connection and check is it valid
cs, dn := db.IfEmptyMakeDefault(modelName, inpConnStr, inpDriver)
srcDb, _, err := db.Open(cs, dn, false)
if err != nil {
return err
}
defer srcDb.Close()
if err := db.CheckOpenmppSchemaVersion(srcDb); err != nil {
return err
}
// open destination database and check is it valid
cs, dn = db.IfEmptyMakeDefault(modelName, outConnStr, outDriver)
dstDb, dbFacet, err := db.Open(cs, dn, true)
if err != nil {
return err
}
defer dstDb.Close()
if err := db.CheckOpenmppSchemaVersion(dstDb); err != nil {
return err
}
// get source model metadata and languages, make a deep copy to use for destination database writing
err = copyDbToDb(srcDb, dstDb, dbFacet, modelName, modelDigest, runOpts.String(doubleFormatArgKey))
if err != nil {
return err
}
return nil
}
// copyDbToDb select from source database and insert or update existing
// model metadata in all languages, model runs, workset(s), modeling tasks and task run history.
//
// Model id's and hId's updated with destination database id's.
// For example, in source db model id can be 11 and in destination it will be 200,
// same for all other id's: type Hid, parameter Hid, table Hid, run id, set id, task id, etc.
func copyDbToDb(
srcDb *sql.DB, dstDb *sql.DB, dbFacet db.Facet, modelName string, modelDigest string, doubleFmt string) error {
// source: get model metadata
srcModel, err := db.GetModel(srcDb, modelName, modelDigest)
if err != nil {
return err
}
modelName = srcModel.Model.Name // set model name: it can be empty and only model digest specified
// source: get list of languages
srcLang, err := db.GetLanguages(srcDb)
if err != nil {
return err
}
// source: get model text (description and notes) in all languages
modelTxt, err := db.GetModelText(srcDb, srcModel.Model.ModelId, "")
if err != nil {
return err
}
// source: get model laguage-specific strings in all languages
mwDef, err := db.GetModelWord(srcDb, srcModel.Model.ModelId, "")
if err != nil {
return err
}
// source: get model profile: default model profile is profile where name = model name
modelProfile, err := db.GetProfile(srcDb, modelName)
if err != nil {
return err
}
// deep copy of model metadata and languages is required
// because during db writing metadata structs updated with destination database id's,
// for example, in source db model id can be 11 and in destination it will be 200,
// same for all other id's: type Hid, parameter Hid, table Hid, run id, set id, task id, etc.
dstModel, err := srcModel.Clone()
if err != nil {
return err
}
dstLang, err := srcLang.Clone()
if err != nil {
return err
}
// destination: insert model metadata into destination database if not exists
if _, err = db.UpdateModel(dstDb, dbFacet, dstModel); err != nil {
return err
}
// destination: insert or update language list
if err = db.UpdateLanguage(dstDb, dstLang); err != nil {
return err
}
// destination: get full list of languages in destination database
dstLang, err = db.GetLanguages(dstDb)
if err != nil {
return err
}
// destination: insert, update or delete model default profile
if err = db.UpdateProfile(dstDb, modelProfile); err != nil {
return err
}
// destination: insert or update model text data (description and notes)
if err = db.UpdateModelText(dstDb, dstModel, dstLang, modelTxt); err != nil {
return err
}
// destination: insert or update model language-specific strings
if err = db.UpdateModelWord(dstDb, dstModel, dstLang, mwDef); err != nil {
return err
}
// source to destination: copy model runs: parameters, output expressions and accumulators
err = copyRunListDbToDb(srcDb, dstDb, srcModel, dstModel, dstLang, doubleFmt)
if err != nil {
return err
}
// source to destination: copy all readonly worksets parameters
err = copyWorksetListDbToDb(srcDb, dstDb, srcModel, dstModel, dstLang)
if err != nil {
return err
}
// source to destination: copy all modeling tasks
err = copyTaskListDbToDb(srcDb, dstDb, srcModel, dstModel, dstLang)
if err != nil {
return err
}
return nil
}