2017-01-14 04:38:40 +01:00
|
|
|
package boilingcore
|
2016-06-12 03:25:00 +02:00
|
|
|
|
|
|
|
import (
|
2016-06-20 07:22:50 +02:00
|
|
|
"fmt"
|
2017-01-16 06:21:04 +01:00
|
|
|
"io/ioutil"
|
2016-06-12 03:25:00 +02:00
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"text/template"
|
|
|
|
|
2017-01-16 06:21:04 +01:00
|
|
|
"github.com/pkg/errors"
|
2016-08-09 09:59:30 +02:00
|
|
|
"github.com/vattle/sqlboiler/bdb"
|
2016-09-15 05:45:09 +02:00
|
|
|
"github.com/vattle/sqlboiler/queries"
|
2016-08-09 09:59:30 +02:00
|
|
|
"github.com/vattle/sqlboiler/strmangle"
|
2016-06-12 03:25:00 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// templateData for sqlboiler templates
|
|
|
|
type templateData struct {
|
2016-09-12 07:30:25 +02:00
|
|
|
Tables []bdb.Table
|
|
|
|
Table bdb.Table
|
|
|
|
|
|
|
|
// Controls what names are output
|
|
|
|
PkgName string
|
|
|
|
Schema string
|
|
|
|
|
|
|
|
// Controls which code is output (mysql vs postgres ...)
|
|
|
|
DriverName string
|
|
|
|
UseLastInsertID bool
|
|
|
|
|
|
|
|
// Turn off auto timestamps or hook generation
|
2016-08-28 16:12:37 +02:00
|
|
|
NoHooks bool
|
|
|
|
NoAutoTimestamps bool
|
2016-09-12 07:30:25 +02:00
|
|
|
|
|
|
|
// Tags control which
|
|
|
|
Tags []string
|
|
|
|
|
|
|
|
// StringFuncs are usable in templates with stringMap
|
|
|
|
StringFuncs map[string]func(string) string
|
|
|
|
|
|
|
|
// Dialect controls quoting
|
2016-09-15 05:45:09 +02:00
|
|
|
Dialect queries.Dialect
|
2016-09-12 07:30:25 +02:00
|
|
|
LQ string
|
|
|
|
RQ string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t templateData) Quotes(s string) string {
|
|
|
|
return fmt.Sprintf("%s%s%s", t.LQ, s, t.RQ)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t templateData) SchemaTable(table string) string {
|
|
|
|
return strmangle.SchemaTable(t.LQ, t.RQ, t.DriverName, t.Schema, table)
|
2016-06-12 03:25:00 +02:00
|
|
|
}
|
|
|
|
|
2016-07-17 08:55:15 +02:00
|
|
|
type templateList struct {
|
|
|
|
*template.Template
|
|
|
|
}
|
|
|
|
|
|
|
|
type templateNameList []string
|
2016-06-12 03:25:00 +02:00
|
|
|
|
2016-07-17 08:55:15 +02:00
|
|
|
func (t templateNameList) Len() int {
|
2016-06-12 03:25:00 +02:00
|
|
|
return len(t)
|
|
|
|
}
|
|
|
|
|
2016-07-17 08:55:15 +02:00
|
|
|
func (t templateNameList) Swap(k, j int) {
|
2016-06-12 03:25:00 +02:00
|
|
|
t[k], t[j] = t[j], t[k]
|
|
|
|
}
|
|
|
|
|
2016-07-17 08:55:15 +02:00
|
|
|
func (t templateNameList) Less(k, j int) bool {
|
2016-06-12 03:25:00 +02:00
|
|
|
// Make sure "struct" goes to the front
|
2016-07-17 08:55:15 +02:00
|
|
|
if t[k] == "struct.tpl" {
|
2016-06-12 03:25:00 +02:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2016-07-17 08:55:15 +02:00
|
|
|
res := strings.Compare(t[k], t[j])
|
2016-06-12 03:25:00 +02:00
|
|
|
if res <= 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2016-07-17 08:55:15 +02:00
|
|
|
// Templates returns the name of all the templates defined in the template list
|
|
|
|
func (t templateList) Templates() []string {
|
|
|
|
tplList := t.Template.Templates()
|
|
|
|
|
|
|
|
if len(tplList) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ret := make([]string, 0, len(tplList))
|
|
|
|
for _, tpl := range tplList {
|
|
|
|
if name := tpl.Name(); strings.HasSuffix(name, ".tpl") {
|
|
|
|
ret = append(ret, name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(templateNameList(ret))
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2016-06-12 03:25:00 +02:00
|
|
|
// loadTemplates loads all of the template files in the specified directory.
|
2016-07-17 08:55:15 +02:00
|
|
|
func loadTemplates(dir string) (*templateList, error) {
|
2016-08-24 06:50:14 +02:00
|
|
|
pattern := filepath.Join(dir, "*.tpl")
|
2016-06-12 03:25:00 +02:00
|
|
|
tpl, err := template.New("").Funcs(templateFunctions).ParseGlob(pattern)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-07-17 08:55:15 +02:00
|
|
|
return &templateList{Template: tpl}, err
|
2016-06-12 03:25:00 +02:00
|
|
|
}
|
|
|
|
|
2017-02-04 17:24:20 +01:00
|
|
|
// loadTemplate loads a single template file
|
|
|
|
func loadTemplate(dir string, filename string) (*template.Template, error) {
|
|
|
|
pattern := filepath.Join(dir, filename)
|
|
|
|
tpl, err := template.New("").Funcs(templateFunctions).ParseFiles(pattern)
|
|
|
|
|
2016-06-12 03:25:00 +02:00
|
|
|
if err != nil {
|
2017-02-04 17:24:20 +01:00
|
|
|
return nil, err
|
2017-01-16 06:21:04 +01:00
|
|
|
}
|
|
|
|
|
2017-02-04 17:24:20 +01:00
|
|
|
return tpl.Lookup(filename), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// replaceTemplate finds the template matching with name and replaces its
|
|
|
|
// contents with the contents of the template located at filename
|
|
|
|
func replaceTemplate(tpl *template.Template, name, filename string) error {
|
2017-01-16 06:21:04 +01:00
|
|
|
if tpl == nil {
|
2017-02-04 17:24:20 +01:00
|
|
|
return fmt.Errorf("template for %s is nil", name)
|
2017-01-16 06:21:04 +01:00
|
|
|
}
|
2017-02-04 17:24:20 +01:00
|
|
|
|
|
|
|
b, err := ioutil.ReadFile(filename)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "failed reading template file: %s", filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
if tpl, err = tpl.New(name).Funcs(templateFunctions).Parse(string(b)); err != nil {
|
|
|
|
return errors.Wrapf(err, "failed to parse template file: %s", filename)
|
2016-06-12 03:25:00 +02:00
|
|
|
}
|
|
|
|
|
2017-02-04 17:24:20 +01:00
|
|
|
return nil
|
2016-06-12 03:25:00 +02:00
|
|
|
}
|
|
|
|
|
2016-11-11 10:01:09 +01:00
|
|
|
// set is to stop duplication from named enums, allowing a template loop
|
|
|
|
// to keep some state
|
|
|
|
type once map[string]struct{}
|
|
|
|
|
|
|
|
func newOnce() once {
|
|
|
|
return make(once)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o once) Has(s string) bool {
|
|
|
|
_, ok := o[s]
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o once) Put(s string) bool {
|
|
|
|
if _, ok := o[s]; ok {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
o[s] = struct{}{}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2016-06-20 07:22:50 +02:00
|
|
|
// templateStringMappers are placed into the data to make it easy to use the
|
|
|
|
// stringMap function.
|
|
|
|
var templateStringMappers = map[string]func(string) string{
|
2016-06-20 07:57:46 +02:00
|
|
|
// String ops
|
2017-02-25 07:27:05 +01:00
|
|
|
"quoteWrap": func(a string) string { return fmt.Sprintf(`"%s"`, a) },
|
|
|
|
"replaceReserved": strmangle.ReplaceReservedWords,
|
2016-06-20 07:57:46 +02:00
|
|
|
|
2016-06-20 07:22:50 +02:00
|
|
|
// Casing
|
|
|
|
"titleCase": strmangle.TitleCase,
|
|
|
|
"camelCase": strmangle.CamelCase,
|
|
|
|
}
|
|
|
|
|
2016-06-12 03:25:00 +02:00
|
|
|
// templateFunctions is a map of all the functions that get passed into the
|
|
|
|
// templates. If you wish to pass a new function into your own template,
|
|
|
|
// add a function pointer here.
|
|
|
|
var templateFunctions = template.FuncMap{
|
2016-06-20 07:22:50 +02:00
|
|
|
// String ops
|
2016-09-12 07:30:25 +02:00
|
|
|
"quoteWrap": func(s string) string { return fmt.Sprintf(`"%s"`, s) },
|
2016-08-14 09:43:30 +02:00
|
|
|
"id": strmangle.Identifier,
|
2016-06-20 07:22:50 +02:00
|
|
|
|
|
|
|
// Pluralization
|
|
|
|
"singular": strmangle.Singular,
|
|
|
|
"plural": strmangle.Plural,
|
|
|
|
|
|
|
|
// Casing
|
|
|
|
"titleCase": strmangle.TitleCase,
|
|
|
|
"camelCase": strmangle.CamelCase,
|
|
|
|
|
|
|
|
// String Slice ops
|
2016-09-04 15:44:54 +02:00
|
|
|
"join": func(sep string, slice []string) string { return strings.Join(slice, sep) },
|
|
|
|
"joinSlices": strmangle.JoinSlices,
|
|
|
|
"stringMap": strmangle.StringMap,
|
|
|
|
"prefixStringSlice": strmangle.PrefixStringSlice,
|
|
|
|
"containsAny": strmangle.ContainsAny,
|
|
|
|
"generateTags": strmangle.GenerateTags,
|
|
|
|
"generateIgnoreTags": strmangle.GenerateIgnoreTags,
|
2016-06-20 07:22:50 +02:00
|
|
|
|
2016-11-11 10:01:09 +01:00
|
|
|
// Enum ops
|
|
|
|
"parseEnumName": strmangle.ParseEnumName,
|
|
|
|
"parseEnumVals": strmangle.ParseEnumVals,
|
|
|
|
"isEnumNormal": strmangle.IsEnumNormal,
|
|
|
|
"shouldTitleCaseEnum": strmangle.ShouldTitleCaseEnum,
|
|
|
|
"onceNew": newOnce,
|
|
|
|
"oncePut": once.Put,
|
|
|
|
"onceHas": once.Has,
|
|
|
|
|
2016-07-13 18:51:40 +02:00
|
|
|
// String Map ops
|
|
|
|
"makeStringMap": strmangle.MakeStringMap,
|
|
|
|
|
2016-08-14 01:03:34 +02:00
|
|
|
// Set operations
|
2016-08-14 09:43:30 +02:00
|
|
|
"setInclude": strmangle.SetInclude,
|
2016-08-14 01:03:34 +02:00
|
|
|
|
2016-06-20 07:22:50 +02:00
|
|
|
// Database related mangling
|
2016-08-14 09:43:30 +02:00
|
|
|
"whereClause": strmangle.WhereClause,
|
2016-06-20 07:22:50 +02:00
|
|
|
|
2016-09-18 08:36:10 +02:00
|
|
|
// Relationship text helpers
|
2016-09-18 19:33:57 +02:00
|
|
|
"txtsFromFKey": txtsFromFKey,
|
|
|
|
"txtsFromOneToOne": txtsFromOneToOne,
|
|
|
|
"txtsFromToMany": txtsFromToMany,
|
2016-07-14 05:31:01 +02:00
|
|
|
|
2016-06-20 07:22:50 +02:00
|
|
|
// dbdrivers ops
|
2017-03-16 08:26:05 +01:00
|
|
|
"filterColumnsByAuto": bdb.FilterColumnsByAuto,
|
2016-08-14 08:54:17 +02:00
|
|
|
"filterColumnsByDefault": bdb.FilterColumnsByDefault,
|
2016-11-11 10:01:09 +01:00
|
|
|
"filterColumnsByEnum": bdb.FilterColumnsByEnum,
|
2016-08-14 08:54:17 +02:00
|
|
|
"sqlColDefinitions": bdb.SQLColDefinitions,
|
|
|
|
"columnNames": bdb.ColumnNames,
|
|
|
|
"columnDBTypes": bdb.ColumnDBTypes,
|
2016-08-18 08:07:39 +02:00
|
|
|
"getTable": bdb.GetTable,
|
2016-06-12 03:25:00 +02:00
|
|
|
}
|