// GenerateSettings generates settings for the ddl package func GenerateSettings(genName string, moduleName string, s *schema.Schema) schema.Generator { settings, ok := s.Generators.Get(genName) if !ok { settings = schema.Generator{} } settings.SetNX("databaseName", stringext.ToFieldName(moduleName)) settings.SetNX("schemaName", stringext.ToFieldName(moduleName)) settings.SetNX("tableName", stringext.ToFieldName(s.Title)) settings.SetNX("roleName", stringext.ToFieldName(moduleName)) // convert []interface to []string grants := settings.GetWithDefault("grants", []string{"ALL"}) grantsI, ok := grants.([]interface{}) grantsS := make([]string, 0) if ok { for _, t := range grantsI { grantsS = append(grantsS, t.(string)) } } else { grantsS = grants.([]string) } settings.Set("grants", grantsS) return settings }
func TestSequence(t *testing.T) { s := &schema.Schema{} if err := json.Unmarshal([]byte(testdata.TestDataFull), s); err != nil { t.Fatal(err.Error()) } s = s.Resolve(s) moduleName := strings.ToLower(s.Title) settings := GenerateSettings(GeneratorName, moduleName, s) index := 0 for _, def := range s.Definitions { // schema should have our generator if !def.Generators.Has(GeneratorName) { continue } settingsDef := SetDefaultSettings(GeneratorName, settings, def) settingsDef.Set("tableName", stringext.ToFieldName(def.Title)) sts, err := DefineSequence(settingsDef, def) if err != nil { t.Fatal(err.Error()) } common.TestEquals(t, expectedSequences[index], string(sts)) index++ } }
// Generate generates the basic CRUD statements for the models func (g *Generator) Generate(req *common.Req, res *common.Res) error { context := req.Context if context == nil || context.Config == nil || !common.IsIn(GeneratorName, context.Config.Generators...) { return nil } if req.Schema == nil { if req.SchemaStr == "" { return errors.New("both schema and string schema is not set") } s := &schema.Schema{} if err := json.Unmarshal([]byte(req.SchemaStr), s); err != nil { return err } req.Schema = s.Resolve(nil) } if req.Schema.Title == "" { return errors.New("Title should be set") } outputs := make([]common.Output, 0) moduleName := stringext.ToFieldName(req.Schema.Title) settings := GenerateSettings(GeneratorName, moduleName, req.Schema) settings.SetNX("rootPathPrefix", "db") rootPathPrefix := settings.Get("rootPathPrefix").(string) fullPathPrefix := req.Context.Config.Target + rootPathPrefix + "/" settings.Set("fullPathPrefix", fullPathPrefix) for _, name := range schema.SortedKeys(req.Schema.Definitions) { def := req.Schema.Definitions[name] // schema should have our generator if !def.Generators.Has(GeneratorName) { continue } settingsDef := SetDefaultSettings(GeneratorName, settings, def) settingsDef.Set("tableName", stringext.ToFieldName(def.Title)) // // generate roles // role, err := DefineRole(settingsDef, def) if err != nil { return err } outputs = append(outputs, common.Output{ Content: role, Path: fmt.Sprintf( "%s/001-%s_roles.sql", fullPathPrefix, settingsDef.Get("databaseName").(string), ), DoNotFormat: true, }) // // generate database // db, err := DefineDatabase(settingsDef, def) if err != nil { return err } outputs = append(outputs, common.Output{ Content: db, Path: fmt.Sprintf( "%s/002-%s_database.sql", fullPathPrefix, settingsDef.Get("databaseName").(string), ), DoNotFormat: true, }) // // generate extenstions // extenstions, err := DefineExtensions(settingsDef, def) if err != nil { return err } outputs = append(outputs, common.Output{ Content: extenstions, Path: fmt.Sprintf( "%s/003-%s_extensions.sql", fullPathPrefix, settingsDef.Get("databaseName").(string)), DoNotFormat: true, }) // // generate schema // sc, err := DefineSchema(settingsDef, def) if err != nil { return err } outputs = append(outputs, common.Output{ Content: sc, Path: fmt.Sprintf( "%s/%s/004-schema.sql", fullPathPrefix, settingsDef.Get("schemaName").(string), ), DoNotFormat: true, }) // // generate sequences // sequence, err := DefineSequence(settingsDef, def) if err != nil { return err } outputs = append(outputs, common.Output{ Content: sequence, Path: fmt.Sprintf( "%s/%s/005-%s-sequence.sql", fullPathPrefix, settingsDef.Get("schemaName").(string), settingsDef.Get("tableName").(string), ), DoNotFormat: true, }) // // generate types // types, err := DefineTypes(settingsDef, def) if err != nil { return err } outputs = append(outputs, common.Output{ Content: types, Path: fmt.Sprintf( "%s/%s/006-%s-types.sql", fullPathPrefix, settingsDef.Get("schemaName").(string), settingsDef.Get("tableName").(string), ), DoNotFormat: true, }) // // generate tables // table, err := DefineTable(settingsDef, def) if err != nil { return err } outputs = append(outputs, common.Output{ Content: table, Path: fmt.Sprintf( "%s/%s/007-%s-table.sql", fullPathPrefix, settingsDef.Get("schemaName").(string), settingsDef.Get("tableName").(string), ), DoNotFormat: true, }) // // generate constraints // constraints, err := DefineConstraints(settingsDef, def) if err != nil { return err } outputs = append(outputs, common.Output{ Content: constraints, Path: fmt.Sprintf( "%s/%s/008-%s-constraints.sql", fullPathPrefix, settingsDef.Get("schemaName").(string), settingsDef.Get("tableName").(string), ), DoNotFormat: true, }) } res.Output = outputs return nil }
// DefineConstraints creates constraints definition for tables func DefineConstraints(settings schema.Generator, s *schema.Schema) ([]byte, error) { primaryKeyConstraint := "" primaryKey := settings.Get("primaryKey") if primaryKey != nil { pmi := primaryKey.([]interface{}) if len(pmi) > 0 { sl := make([]string, len(pmi)) for i, pm := range pmi { sl[i] = stringext.ToFieldName(pm.(string)) } primaryKeyConstraint = fmt.Sprintf( "ALTER TABLE %q.%q ADD PRIMARY KEY (%q) NOT DEFERRABLE INITIALLY IMMEDIATE;\n", settings.Get("schemaName"), settings.Get("tableName"), strings.Join(sl, ", "), ) primaryKeyConstraint = fmt.Sprintf("-------------------------------\n-- Primary key structure for table %s\n-- ----------------------------\n%s", settings.Get("tableName"), primaryKeyConstraint, ) } } uniqueKeyConstraints := "" uniqueKeys := settings.Get("uniqueKeys") if uniqueKeys != nil { ukci := uniqueKeys.([]interface{}) if len(ukci) > 0 { for _, ukc := range ukci { ukcs := ukc.([]interface{}) ukcsps := make([]string, len(ukcs)) for i, ukc := range ukcs { ukcsps[i] = stringext.ToFieldName(ukc.(string)) } keyName := fmt.Sprintf( "%s_%s_%s", stringext.ToFieldName("key"), stringext.ToFieldName(settings.Get("tableName").(string)), strings.Join(ukcsps, "_"), ) uniqueKeyConstraints += fmt.Sprintf( "ALTER TABLE %q.%q ADD CONSTRAINT %q UNIQUE (\"%s\") NOT DEFERRABLE INITIALLY IMMEDIATE;\n", settings.Get("schemaName"), settings.Get("tableName"), keyName, strings.Join(ukcsps, "\", \""), ) } uniqueKeyConstraints = fmt.Sprintf("-------------------------------\n-- Unique key structure for table %s\n-- ----------------------------\n%s", settings.Get("tableName"), uniqueKeyConstraints, ) } } foreignKeyConstraints := "" foreignKeys := settings.Get("foreignKeys") if foreignKeys != nil { fkci := foreignKeys.([]interface{}) if len(fkci) > 0 { for _, fkc := range fkci { fkcs := fkc.([]interface{}) localField := stringext.ToFieldName(fkcs[0].(string)) refFields := strings.Split(fkcs[1].(string), ".") if len(refFields) != 3 { return nil, fmt.Errorf("need schemaName.tableName.fieldName") } keyName := fmt.Sprintf( "%s_%s_%s", stringext.ToFieldName("fkey"), stringext.ToFieldName(settings.Get("tableName").(string)), localField, ) foreignKeyConstraints += fmt.Sprintf( "ALTER TABLE %q.%q ADD CONSTRAINT %q FOREIGN KEY (\"%s\") REFERENCES %s.%s (%s) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE;\n", settings.Get("schemaName"), settings.Get("tableName"), keyName, localField, stringext.ToFieldName(refFields[0]), // first item schema name stringext.ToFieldName(refFields[1]), // second item table name stringext.ToFieldName(refFields[2]), // third item field name ) foreignKeyConstraints = fmt.Sprintf("-------------------------------\n-- Foreign keys structure for table %s\n-- ----------------------------\n%s", settings.Get("tableName"), foreignKeyConstraints, ) } } } return clean([]byte(primaryKeyConstraint + uniqueKeyConstraints + foreignKeyConstraints)), nil }
// GenerateSQLField creates a definition line for a given coloumn func GenerateSQLField(settings schema.Generator, s *schema.Schema) (res string) { propertyName := s.Title schemaName := settings.Get("schemaName").(string) tableName := settings.Get("tableName").(string) property := s fieldName := stringext.ToFieldName(propertyName) // transpiled version of property if property.Title != "" { fieldName = stringext.ToFieldName(property.Title) } fieldType := "" // will hold the type for coloumn switch strings.ToLower(property.Type.(string)) { case "boolean": fieldType = "BOOLEAN" case "string": switch property.Format { case "date-time": fieldType = "TIMESTAMP (6) WITH TIME ZONE" case "UUID": fieldType = "UUID" default: typeName := "TEXT" if property.MaxLength > 0 { // if schema defines a max length, no need to use text typeName = fmt.Sprintf("VARCHAR (%d)", property.MaxLength) } fieldType = fmt.Sprintf("%s COLLATE \"default\"", typeName) } case "number": fieldType = "NUMERIC" switch property.Format { case "int64", "uint64": fieldType = "BIGINT" case "integer", "int", "int32", "uint", "uint32": fieldType = "INTEGER" case "int8", "uint8", "int16", "uint16": fieldType = "SMALLINT" case "float32", "float64": fieldType = "NUMERIC" } case "any": panic("should specify type") case "array": panic("array not supported") case "object", "config": // TODO implement embedded struct table creation res = "" case "null": res = "" case "error": res = "" case "custom": res = "" default: panic("unknown field") } // override if it is an enum field if len(property.Enum) > 0 { fieldType = fmt.Sprintf( "%q.\"%s_%s_enum\"", schemaName, stringext.ToFieldName(tableName), stringext.ToFieldName(propertyName), ) } res = fmt.Sprintf( "%q %s %s %s %s,", // first, name comes fieldName, // then type of the coloumn fieldType, // generate default value if exists generateDefaultValue(schemaName, fieldName, tableName, property), // generate not null statement, if required generateNotNull(s, propertyName), // generate validators generateCheckStatements(tableName, fieldName, property), ) return res }