// pluralCamelNameType takes a type, and returns its type converted // to camel_case and pluralised. func pluralCamelNameType(typ reflect.Type) string { t := fmt.Sprintf("%v", typ) a := strings.Split(t, ".") t1 := a[len(a)-1] t2 := snaker.CamelToSnake(t1) t3 := inflector.Pluralize(t2) return t3 }
// pluralCamelName takes an interface, and returns its type converted // to camel_case and pluralised. eg. pluralCamelName(ImportantPerson{}) // should return "important_people" func pluralCamelName(i interface{}) string { t := fmt.Sprintf("%T", i) a := strings.Split(t, ".") t1 := a[len(a)-1] t2 := snaker.CamelToSnake(t1) t3 := inflector.Pluralize(t2) return t3 }
func main() { for _, s := range singulars { fmt.Printf("Plural of %v = %v\n", s, inflector.Pluralize(s)) } fmt.Println() for _, s := range plurals { fmt.Printf("Singular of %v = %v\n", s, inflector.Singularize(s)) } }
func GenerateModels(s *models.Schema) (map[string][]byte, error) { modelSrc := make(map[string][]byte) for _, table := range s.Tables { buffer := bytes.NewBuffer([]byte{}) structName := inflector.Singularize(strings.Title(table.Name)) buffer.WriteString(fmt.Sprintf("\n// %s is a generated struct from a %s database. See github.com/alistanis/stg for more information.", structName, s.Adapter)) buffer.WriteString(fmt.Sprintf("\ntype %s struct {\n", structName)) for _, row := range table.Rows { buffer.WriteString(fmt.Sprintf(" %s", strings.Title(row.Field))) t := row.Type switch { case strings.Contains(t, "int"), strings.Contains(t, "numeric"): buffer.WriteString(fmt.Sprintf(" int `db:\"%s\"` \n", row.Field)) case strings.Contains(t, "varchar"), strings.Contains(t, "text"), strings.Contains(t, "char"): buffer.WriteString(fmt.Sprintf(" string `db:\"%s\"` \n", row.Field)) case strings.Contains(t, "real"), strings.Contains(t, "float"): buffer.WriteString(fmt.Sprintf(" float64 `db:\"%s\"` \n", row.Field)) case strings.Contains(t, "bool"): buffer.WriteString(fmt.Sprintf(" bool `db:\"%s\"` \n", row.Field)) case strings.Contains(t, "enum"): buffer.WriteString(fmt.Sprintf(" interface{} `db:\"%s\"` \n", row.Field)) case strings.Contains(t, "blob"), strings.Contains(t, "binary"): buffer.WriteString(fmt.Sprintf(" []byte `db:\"%s\"` \n", row.Field)) default: return nil, errors.New("Unsupported type") } } buffer.WriteString("\n}\n") buffer.WriteString(fmt.Sprintf(`var ( %s = &%s{} ) `, inflector.Pluralize(strings.Title(table.Name)), strings.Title(table.Name))) methods, err := GenerateMethods(table, s.Adapter) if err != nil { return nil, err } for _, m := range methods { buffer.WriteString(m) } src, err := format.Source(buffer.Bytes()) if err != nil { return nil, err } buffer.Reset() modelSrc[strings.ToLower(table.Name)] = src } return modelSrc, nil }
// BuildIndexFuncName builds the index func name for an index and its supplied // fields. func (a *ArgType) BuildIndexFuncName(ixTpl *Index) { // build func name funcName := ixTpl.Type.Name if !ixTpl.Index.IsUnique { funcName = inflector.Pluralize(ixTpl.Type.Name) } funcName = funcName + "By" // add param names paramNames := []string{} ixName := fmtIndexName(ixTpl.Index.IndexName, ixTpl.Type.Table.TableName) if a.UseIndexNames && ixName != "" { paramNames = append(paramNames, ixName) } else { for _, f := range ixTpl.Fields { paramNames = append(paramNames, f.Name) } } // store resulting name back ixTpl.FuncName = funcName + strings.Join(paramNames, "") }
func Plural(s string) string { return inflector.Pluralize(s) }
// Pluralize returns the pluralization of a noun. func Pluralize(word string) string { return inflector.Pluralize(word) }
func (n *Naming) Pluralize() { n.ResourceName = inflector.Pluralize(n.ResourceName) }
func (h HasOne) TableName() string { return inflector.Pluralize(toSnakeCase(h.Func())) }
// PgLoadIdx loads indexes from the database. func PgLoadIdx(args *internal.ArgType, db *sql.DB, typeMap map[string]*bytes.Buffer, tableMap map[string]*templates.TableTemplate) (map[string]*templates.IdxTemplate, error) { var err error // load idx's idxMap := map[string]*templates.IdxTemplate{} for _, t := range tableMap { // find relevant columns fields := []*models.Column{} for _, f := range t.Fields { if f.IsIndex && !f.IsForeignKey { if _, ok := idxMap[f.IndexName]; !ok { i := &templates.IdxTemplate{ Type: t.Type, Name: snaker.SnakeToCamel(f.IndexName), TableSchema: t.TableSchema, TableName: f.TableName, IndexName: f.IndexName, IsUnique: f.IsUnique, Fields: fields, Table: t, } // non unique lookup if !f.IsUnique { idxName := i.IndexName // chop off tablename_ if strings.HasPrefix(idxName, f.TableName+"_") { idxName = idxName[len(f.TableName)+1:] } // chop off _idx or _index switch { case strings.HasSuffix(idxName, "_idx"): idxName = idxName[:len(idxName)-len("_idx")] case strings.HasSuffix(idxName, "_index"): idxName = idxName[:len(idxName)-len("_index")] } i.Name = snaker.SnakeToCamel(idxName) i.Plural = inflector.Pluralize(t.Type) } idxMap[f.IndexName] = i } idxMap[f.IndexName].Fields = append(idxMap[f.IndexName].Fields, f) } } } // idx keys idxKeys := []string{} for k := range idxMap { idxKeys = append(idxKeys, k) } sort.Strings(idxKeys) // generate templates for _, k := range idxKeys { buf := GetBuf(typeMap, strings.ToLower(idxMap[k].Type)) err = templates.Tpls["postgres.idx.go.tpl"].Execute(buf, idxMap[k]) if err != nil { return nil, err } } return idxMap, nil }
func (s structType) TableName() string { return toSnakeCase(inflector.Pluralize(s.Name)) }
func (sd *ShortDesc) Pluralize() string { return inflector.Pluralize(sd.Value) }
func PluralizedModelName(m interface{}) (string, error) { typ := reflect.TypeOf(m) start := strings.Index(typ.String(), ".") + 1 end := len(typ.String()) return inflector.Pluralize(strings.ToLower(typ.String()[start:end])), nil }
func (i *extensionPoint) Var() string { return inflector.Pluralize(i.Name) }
func handleString(schemas []ColumnSchema, table string) string { pk := primaryKey(schemas, table) updateLastUpdated := hasLastUpdated(schemas, table) out := "" out += "// @Title get" + formatName(table) + "ById\n" out += "// @Description retrieves the " + table + " information for a certain id\n" out += "// @Accept application/json\n" out += "// @Param id path int false \"The row id\"\n" out += "// @Success 200 {array} " + formatName(table) + "\n" out += "// @Resource /api/2.0\n" out += "// @Router /api/2.0/" + table + "/{id} [get]\n" out += "func get" + inflector.Singularize(formatName(table)) + "(" + getPkGoFuncParamString(pk) + ", db *sqlx.DB) (interface{}, error) {\n" out += " ret := []" + formatName(table) + "{}\n" out += " arg := " + formatName(table) + "{}\n" out += setStructPkFields(pk) out += " queryStr := \"select *, " + selfQueryStr(pk, table) + "\"\n" out += setFkHALQueryStr(schemas, table) out += " queryStr += \" from " + table + " " + pkWhereStr(pk) + "\"\n" out += " nstmt, err := db.PrepareNamed(queryStr)\n" out += " err = nstmt.Select(&ret, arg)\n" out += " if err != nil {\n" out += " log.Println(err)\n" out += " return nil, err\n" out += " }\n" out += " nstmt.Close()\n" out += " return ret, nil\n" out += "}\n\n" out += "// @Title get" + formatName(table) + "s\n" out += "// @Description retrieves the " + table + "\n" out += "// @Accept application/json\n" out += "// @Success 200 {array} " + formatName(table) + "\n" out += "// @Resource /api/2.0\n" out += "// @Router /api/2.0/" + table + " [get]\n" out += "func get" + inflector.Pluralize(formatName(table)) + "(db *sqlx.DB) (interface{}, error) {\n" out += " ret := []" + formatName(table) + "{}\n" out += " queryStr := \"select *, " + selfQueryStr(pk, table) + "\"\n" out += setFkHALQueryStr(schemas, table) out += "queryStr += \" from " + table + "\"\n" out += " err := db.Select(&ret, queryStr)\n" out += " if err != nil {\n" out += " log.Println(err)\n" out += " return nil, err\n" out += " }\n" out += " return ret, nil\n" out += "}\n\n" out += "// @Title post" + formatName(table) + "\n" out += "// @Description enter a new " + table + "\n" out += "// @Accept application/json\n" out += "// @Param Body body " + formatName(table) + " true \"" + formatName(table) + " object that should be added to the table\"\n" out += "// @Success 200 {object} output_format.ApiWrapper\n" out += "// @Resource /api/2.0\n" out += "// @Router /api/2.0/" + table + " [post]\n" out += "func post" + inflector.Singularize(formatName(table)) + "(payload []byte, db *sqlx.DB) (interface{}, error) {\n" out += " var v " + formatName(table) + "\n" out += " err := json.Unmarshal(payload, &v)\n" out += " if err != nil {\n" out += " log.Println(err)\n" out += " return nil, err\n" out += " }\n" out += genInsertVarLines(schemas, table) out += " result, err := db.NamedExec(sqlString, v)\n" out += " if err != nil {\n" out += " log.Println(err)\n" out += " return nil, err\n" out += " }\n" out += " return result, err\n" out += "}\n\n" out += "// @Title put" + formatName(table) + "\n" out += "// @Description modify an existing " + table + "entry\n" out += "// @Accept application/json\n" out += "// @Param id path int true \"The row id\"\n" out += "// @Param Body body " + formatName(table) + " true \"" + formatName(table) + " object that should be added to the table\"\n" out += "// @Success 200 {object} output_format.ApiWrapper\n" out += "// @Resource /api/2.0\n" out += "// @Router /api/2.0/" + table + "/{id} [put]\n" out += "func put" + inflector.Singularize(formatName(table)) + "(" + getPkGoFuncParamString(pk) + ", payload []byte, db *sqlx.DB) (interface{}, error) {\n" out += " var arg " + formatName(table) + "\n" out += " err := json.Unmarshal(payload, &arg)\n" out += setStructPkFields(pk) out += " if err != nil {\n" out += " log.Println(err)\n" out += " return nil, err\n" out += " }\n" if updateLastUpdated { out += " arg.LastUpdated = time.Now()\n" } out += genUpdateVarLines(schemas, table) out += " result, err := db.NamedExec(sqlString, arg)\n" out += " if err != nil {\n" out += " log.Println(err)\n" out += " return nil, err\n" out += " }\n" out += " return result, err\n" out += "}\n\n" out += "// @Title del" + formatName(table) + "ById\n" out += "// @Description deletes " + table + " information for a certain id\n" out += "// @Accept application/json\n" out += "// @Param id path int false \"The row id\"\n" out += "// @Success 200 {array} " + formatName(table) + "\n" out += "// @Resource /api/2.0\n" out += "// @Router /api/2.0/" + table + "/{id} [delete]\n" out += "func del" + inflector.Singularize(formatName(table)) + "(" + getPkGoFuncParamString(pk) + ", db *sqlx.DB) (interface{}, error) {\n" out += " arg := " + formatName(table) + "{}\n" out += setStructPkFields(pk) out += " result, err := db.NamedExec(\"DELETE FROM " + table + " " + pkWhereStr(pk) + "\", arg)\n" out += " if err != nil {\n" out += " log.Println(err)\n" out += " return nil, err\n" out += " }\n" out += " return result, err\n" out += "}\n\n" return out }
func (str String) Pluralize() string { return inflector.Pluralize(string(str)) }
func (b BelongsTo) TableName() string { return inflector.Pluralize(toSnakeCase(b.Func())) }
// PgParseQuery parses the query and generates a type for it. func PgParseQuery(args *internal.ArgType, db *sql.DB, typeMap map[string]*bytes.Buffer) error { var err error // parse supplied query queryStr, params := parseQuery(args, args.Query, "$%d") inspectStr, _ := parseQuery(args, args.Query, "NULL") // strip out if args.QueryStrip { queryStr = queryStripRE.ReplaceAllString(queryStr, "") } // split up query and inspect based on lines query := strings.Split(queryStr, "\n") inspect := strings.Split(inspectStr, "\n") // build query comments with stripped values // FIXME: this is off by one, because of golang template syntax limitations queryComments := make([]string, len(query)+1) if args.QueryStrip { for i, l := range inspect { pos := queryStripRE.FindStringIndex(l) if pos != nil { queryComments[i+1] = l[pos[0]:pos[1]] } else { queryComments[i+1] = "" } } } // trim whitespace if applicable if args.QueryTrim { for n, l := range query { query[n] = strings.TrimSpace(l) if n < len(query)-1 { query[n] = query[n] + " " } } for n, l := range inspect { inspect[n] = strings.TrimSpace(l) if n < len(inspect)-1 { inspect[n] = inspect[n] + " " } } } // create temporary view xoid xoid := "_xo_" + genRandomID() viewq := `CREATE TEMPORARY VIEW ` + xoid + ` AS (` + strings.Join(inspect, "\n") + `)` _, err = db.Exec(viewq) if err != nil { return err } // determine schema name temporary view was created on // sql query var nspq = `SELECT n.nspname ` + `FROM pg_class c ` + `JOIN pg_namespace n ON n.oid = c.relnamespace ` + `WHERE n.nspname LIKE 'pg_temp%' AND c.relname = $1` // run schema query var schema string err = db.QueryRow(nspq, xoid).Scan(&schema) if err != nil { return err } // load column information ("v" == view) cols, err := models.ColumnsByRelkindSchema(db, "v", schema) if err != nil { return err } // create template for query type typeTpl := &templates.TableTemplate{ Type: args.QueryType, TableSchema: args.Schema, Fields: []*models.Column{}, Comment: args.QueryTypeComment, } // process columns for _, c := range cols { c.Field = snaker.SnakeToCamel(c.ColumnName) c.Len, c.NilType, c.Type = PgParseType(args, c.DataType, false) typeTpl.Fields = append(typeTpl.Fields, c) } // generate query type template buf := GetBuf(typeMap, strings.ToLower(args.QueryType)) err = templates.Tpls["postgres.model.go.tpl"].Execute(buf, typeTpl) if err != nil { return err } // build func name funcName := args.QueryFunc if funcName == "" { // no func name specified, so generate based on type if args.QueryOnlyOne { funcName = args.QueryType } else { funcName = inflector.Pluralize(args.QueryType) } // affix any params if len(params) == 0 { funcName = "Get" + funcName } else { funcName = funcName + "By" for _, p := range params { funcName = funcName + strings.ToUpper(p[0][:1]) + p[0][1:] } } } // create func template funcTpl := &templates.FuncTemplate{ Name: funcName, Type: args.QueryType, Query: query, QueryComments: queryComments, Parameters: params, OnlyOne: args.QueryOnlyOne, Comment: args.QueryFuncComment, Table: typeTpl, } // generate template err = templates.Tpls["postgres.func.go.tpl"].Execute(buf, funcTpl) if err != nil { return err } return nil }
// ParseQuery satisfies Loader's ParseQuery. func (tl TypeLoader) ParseQuery(args *ArgType) error { var err error // parse supplied query queryStr, params := args.ParseQuery(tl.Mask(), true) inspectStr, _ := args.ParseQuery("NULL", false) // split up query and inspect based on lines query := strings.Split(queryStr, "\n") inspect := strings.Split(inspectStr, "\n") // query comment placeholder queryComments := make([]string, len(query)+1) // trim whitespace if applicable if args.QueryTrim { for n, l := range query { query[n] = strings.TrimSpace(l) if n < len(query)-1 { query[n] = query[n] + " " } } for n, l := range inspect { inspect[n] = strings.TrimSpace(l) if n < len(inspect)-1 { inspect[n] = inspect[n] + " " } } } // query strip if args.QueryStrip && tl.QueryStrip != nil { tl.QueryStrip(query, queryComments) } // create template for query type typeTpl := &Type{ Name: args.QueryType, RelType: Table, Fields: []*Field{}, Table: &models.Table{ TableName: "[custom " + strings.ToLower(snaker.CamelToSnake(args.QueryType)) + "]", }, Comment: args.QueryTypeComment, } if args.QueryFields == "" { // if no query fields specified, then pass to inspector colList, err := tl.QueryColumnList(args, inspect) if err != nil { return err } // process columns for _, c := range colList { f := &Field{ Name: SnakeToIdentifier(c.ColumnName), Col: c, } f.Len, f.NilType, f.Type = tl.ParseType(args, c.DataType, false) typeTpl.Fields = append(typeTpl.Fields, f) } } else { // extract fields from query fields for _, qf := range strings.Split(args.QueryFields, ",") { qf = strings.TrimSpace(qf) colName := qf colType := "string" i := strings.Index(qf, " ") if i != -1 { colName = qf[:i] colType = qf[i+1:] } typeTpl.Fields = append(typeTpl.Fields, &Field{ Name: colName, Type: colType, Col: &models.Column{ ColumnName: snaker.CamelToSnake(colName), }, }) } } // generate query type template err = args.ExecuteTemplate(QueryTypeTemplate, args.QueryType, "", typeTpl) if err != nil { return err } // build func name funcName := args.QueryFunc if funcName == "" { // no func name specified, so generate based on type if args.QueryOnlyOne { funcName = args.QueryType } else { funcName = inflector.Pluralize(args.QueryType) } // affix any params if len(params) == 0 { funcName = "Get" + funcName } else { funcName = funcName + "By" for _, p := range params { funcName = funcName + strings.ToUpper(p.Name[:1]) + p.Name[1:] } } } // create func template queryTpl := &Query{ Name: funcName, Query: query, QueryComments: queryComments, QueryParams: params, OnlyOne: args.QueryOnlyOne, Interpolate: args.QueryInterpolate, Type: typeTpl, Comment: args.QueryFuncComment, } // generate template err = args.ExecuteTemplate(QueryTemplate, args.QueryType, "", queryTpl) if err != nil { return err } return nil }