package orm

import (
	
	
	
	
	
	
	
	
	

	
	

	

	
	
	
	
)

const (
	beforeScanHookFlag = uint16(1) << iota
	afterScanHookFlag
	afterSelectHookFlag
	beforeInsertHookFlag
	afterInsertHookFlag
	beforeUpdateHookFlag
	afterUpdateHookFlag
	beforeDeleteHookFlag
	afterDeleteHookFlag
	discardUnknownColumnsFlag
)

var (
	timeType           = reflect.TypeOf((*time.Time)(nil)).Elem()
	nullTimeType       = reflect.TypeOf((*types.NullTime)(nil)).Elem()
	sqlNullTimeType    = reflect.TypeOf((*sql.NullTime)(nil)).Elem()
	ipType             = reflect.TypeOf((*net.IP)(nil)).Elem()
	ipNetType          = reflect.TypeOf((*net.IPNet)(nil)).Elem()
	scannerType        = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
	nullBoolType       = reflect.TypeOf((*sql.NullBool)(nil)).Elem()
	nullFloatType      = reflect.TypeOf((*sql.NullFloat64)(nil)).Elem()
	nullIntType        = reflect.TypeOf((*sql.NullInt64)(nil)).Elem()
	nullStringType     = reflect.TypeOf((*sql.NullString)(nil)).Elem()
	jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem()
)

var tableNameInflector = inflection.Plural

// SetTableNameInflector overrides the default func that pluralizes
// model name to get table name, e.g. my_article becomes my_articles.
func ( func(string) string) {
	tableNameInflector = 
}

// Table represents a SQL table created from Go struct.
type Table struct {
	Type       reflect.Type
	zeroStruct reflect.Value

	TypeName  string
	Alias     types.Safe
	ModelName string

	SQLName           types.Safe
	SQLNameForSelects types.Safe

	Tablespace types.Safe

	PartitionBy string

	allFields     []*Field // read only
	skippedFields []*Field

	Fields      []*Field // PKs + DataFields
	PKs         []*Field
	DataFields  []*Field
	fieldsMapMu sync.RWMutex
	FieldsMap   map[string]*Field

	Methods   map[string]*Method
	Relations map[string]*Relation
	Unique    map[string][]*Field

	SoftDeleteField    *Field
	SetSoftDeleteField func(fv reflect.Value) error

	flags uint16
}

func ( reflect.Type) *Table {
	 := new(Table)
	.Type = 
	.zeroStruct = reflect.New(.Type).Elem()
	.TypeName = internal.ToExported(.Type.Name())
	.ModelName = internal.Underscore(.Type.Name())
	 := tableNameInflector(.ModelName)
	.setName(quoteIdent())
	.Alias = quoteIdent(.ModelName)

	 = reflect.PtrTo(.Type)
	if .Implements(beforeScanHookType) {
		.setFlag(beforeScanHookFlag)
	}
	if .Implements(afterScanHookType) {
		.setFlag(afterScanHookFlag)
	}
	if .Implements(afterSelectHookType) {
		.setFlag(afterSelectHookFlag)
	}
	if .Implements(beforeInsertHookType) {
		.setFlag(beforeInsertHookFlag)
	}
	if .Implements(afterInsertHookType) {
		.setFlag(afterInsertHookFlag)
	}
	if .Implements(beforeUpdateHookType) {
		.setFlag(beforeUpdateHookFlag)
	}
	if .Implements(afterUpdateHookType) {
		.setFlag(afterUpdateHookFlag)
	}
	if .Implements(beforeDeleteHookType) {
		.setFlag(beforeDeleteHookFlag)
	}
	if .Implements(afterDeleteHookType) {
		.setFlag(afterDeleteHookFlag)
	}

	return 
}

func ( *Table) () {
	.initFields()
	.initMethods()
}

func ( *Table) () {
	.initInlines()
	.initRelations()
	.skippedFields = nil
}

func ( *Table) ( types.Safe) {
	.SQLName = 
	.SQLNameForSelects = 
	if .Alias == "" {
		.Alias = 
	}
}

func ( *Table) () string {
	return "model=" + .TypeName
}

func ( *Table) ( uint16) {
	.flags |= 
}

func ( *Table) ( uint16) bool {
	if  == nil {
		return false
	}
	return .flags& != 0
}

func ( *Table) () error {
	if len(.PKs) == 0 {
		return fmt.Errorf("pg: %s does not have primary keys", )
	}
	return nil
}

func ( *Table) () error {
	if .SoftDeleteField == nil {
		return fmt.Errorf("pg: %s does not support soft deletes", )
	}
	return nil
}

func ( *Table) ( *Field) {
	.Fields = append(.Fields, )
	if .hasFlag(PrimaryKeyFlag) {
		.PKs = append(.PKs, )
	} else {
		.DataFields = append(.DataFields, )
	}
	.FieldsMap[.SQLName] = 
}

func ( *Table) ( *Field) {
	.Fields = removeField(.Fields, )
	if .hasFlag(PrimaryKeyFlag) {
		.PKs = removeField(.PKs, )
	} else {
		.DataFields = removeField(.DataFields, )
	}
	delete(.FieldsMap, .SQLName)
}

func ( []*Field,  *Field) []*Field {
	for ,  := range  {
		if  ==  {
			 = append([:], [+1:]...)
		}
	}
	return 
}

func ( *Table) ( string) *Field {
	.fieldsMapMu.RLock()
	 := .FieldsMap[]
	.fieldsMapMu.RUnlock()
	return 
}

func ( *Table) ( string) bool {
	,  := .FieldsMap[]
	return 
}

func ( *Table) ( string) (*Field, error) {
	,  := .FieldsMap[]
	if ! {
		return nil, fmt.Errorf("pg: %s does not have column=%s", , )
	}
	return , nil
}

func ( *Table) ( []byte,  reflect.Value,  string) ([]byte, bool) {
	,  := .FieldsMap[]
	if  {
		 = .AppendValue(, , 1)
		return , true
	}

	,  := .Methods[]
	if  {
		 = .AppendValue(, .Addr(), 1)
		return , true
	}

	return , false
}

func ( *Table) () {
	.Fields = make([]*Field, 0, .Type.NumField())
	.FieldsMap = make(map[string]*Field, .Type.NumField())
	.addFields(.Type, nil)
}

func ( *Table) ( reflect.Type,  []int) {
	for  := 0;  < .NumField(); ++ {
		 := .Field()

		// Make a copy so slice is not shared between fields.
		 := make([]int, len())
		copy(, )

		if .Anonymous {
			if .Tag.Get("sql") == "-" || .Tag.Get("pg") == "-" {
				continue
			}

			 := indirectType(.Type)
			if .Kind() != reflect.Struct {
				continue
			}
			.(, append(, .Index...))

			 := tagparser.Parse(.Tag.Get("pg"))
			if ,  := .Options["inherit"];  {
				 := _tables.get(, true)
				.TypeName = .TypeName
				.SQLName = .SQLName
				.SQLNameForSelects = .SQLNameForSelects
				.Alias = .Alias
				.ModelName = .ModelName
			}

			continue
		}

		 := .newField(, )
		if  != nil {
			.AddField()
		}
	}
}

//nolint
func ( *Table) ( reflect.StructField,  []int) *Field {
	 := tagparser.Parse(.Tag.Get("pg"))

	switch .Name {
	case "tableName":
		if len() > 0 {
			return nil
		}

		if isKnownTableOption(.Name) {
			internal.Warn.Printf(
				"%s.%s tag name %q is also an option name; is it a mistake?",
				.TypeName, .Name, .Name,
			)
		}

		for  := range .Options {
			if !isKnownTableOption() {
				internal.Warn.Printf("%s.%s has unknown tag option: %q", .TypeName, .Name, )
			}
		}

		if ,  := .Options["tablespace"];  {
			,  := tagparser.Unquote()
			.Tablespace = quoteIdent()
		}

		,  := .Options["partition_by"]
		if ! {
			,  = .Options["partitionBy"]
			if  {
				internal.Deprecated.Printf("partitionBy is renamed to partition_by")
			}
		}
		if  {
			,  := tagparser.Unquote()
			.PartitionBy = 
		}

		if .Name == "_" {
			.setName("")
		} else if .Name != "" {
			,  := tagparser.Unquote(.Name)
			.setName(types.Safe(quoteTableName()))
		}

		if ,  := .Options["select"];  {
			, _ = tagparser.Unquote()
			.SQLNameForSelects = types.Safe(quoteTableName())
		}

		if ,  := .Options["alias"];  {
			, _ = tagparser.Unquote()
			.Alias = quoteIdent()
		}

		 := tagparser.Parse(.Tag.Get("pg"))
		if ,  := .Options["discard_unknown_columns"];  {
			.setFlag(discardUnknownColumnsFlag)
		}

		return nil
	}

	if .PkgPath != "" {
		return nil
	}

	 := internal.Underscore(.Name)

	if .Name !=  && isKnownFieldOption(.Name) {
		internal.Warn.Printf(
			"%s.%s tag name %q is also an option name; is it a mistake?",
			.TypeName, .Name, .Name,
		)
	}

	for  := range .Options {
		if !isKnownFieldOption() {
			internal.Warn.Printf("%s.%s has unknown tag option: %q", .TypeName, .Name, )
		}
	}

	 := .Name == "-"
	if ! && .Name != "" {
		 = .Name
	}

	 = append(, .Index...)
	if  := .getField();  != nil {
		if indexEqual(.Index, ) {
			return 
		}
		.RemoveField()
	}

	 := &Field{
		Field: ,
		Type:  indirectType(.Type),

		GoName:  .Name,
		SQLName: ,
		Column:  quoteIdent(),

		Index: ,
	}

	if ,  := .Options["notnull"];  {
		.setFlag(NotNullFlag)
	}
	if ,  := .Options["unique"];  {
		if  == "" {
			.setFlag(UniqueFlag)
		}
		// Split the value by comma, this will allow multiple names to be specified.
		// We can use this to create multiple named unique constraints where a single column
		// might be included in multiple constraints.
		, _ = tagparser.Unquote()
		for ,  := range strings.Split(, ",") {
			if .Unique == nil {
				.Unique = make(map[string][]*Field)
			}
			.Unique[] = append(.Unique[], )
		}
	}
	if ,  := .Options["default"];  {
		,  = tagparser.Unquote()
		if  {
			.Default = types.Safe(types.AppendString(nil, , 1))
		} else {
			.Default = types.Safe()
		}
	}

	//nolint
	if ,  := .Options["pk"];  {
		.setFlag(PrimaryKeyFlag)
	} else if strings.HasSuffix(.SQLName, "_id") ||
		strings.HasSuffix(.SQLName, "_uuid") {
		.setFlag(ForeignKeyFlag)
	} else if strings.HasPrefix(.SQLName, "fk_") {
		.setFlag(ForeignKeyFlag)
	} else if len(.PKs) == 0 && !.HasOption("nopk") {
		switch .SQLName {
		case "id", "uuid", "pk_" + .ModelName:
			.setFlag(PrimaryKeyFlag)
		}
	}

	if ,  := .Options["use_zero"];  {
		.setFlag(UseZeroFlag)
	}
	if ,  := .Options["array"];  {
		.setFlag(ArrayFlag)
	}

	.SQLType = fieldSQLType(, )
	if strings.HasSuffix(.SQLType, "[]") {
		.setFlag(ArrayFlag)
	}

	if ,  := .Options["on_delete"];  {
		.OnDelete = 
	}

	if ,  := .Options["on_update"];  {
		.OnUpdate = 
	}

	if ,  := .Options["composite"];  {
		.append = compositeAppender(.Type)
		.scan = compositeScanner(.Type)
	} else if ,  := .Options["json_use_number"];  {
		.append = types.Appender(.Type)
		.scan = scanJSONValue
	} else if .hasFlag(ArrayFlag) {
		.append = types.ArrayAppender(.Type)
		.scan = types.ArrayScanner(.Type)
	} else if ,  := .Options["hstore"];  {
		.append = types.HstoreAppender(.Type)
		.scan = types.HstoreScanner(.Type)
	} else if .SQLType == pgTypeBigint && .Type.Kind() == reflect.Uint64 {
		if .Type.Kind() == reflect.Ptr {
			.append = appendUintPtrAsInt
		} else {
			.append = appendUintAsInt
		}
		.scan = types.Scanner(.Type)
	} else if ,  := .Options["msgpack"];  {
		.append = msgpackAppender(.Type)
		.scan = msgpackScanner(.Type)
	} else {
		.append = types.Appender(.Type)
		.scan = types.Scanner(.Type)
	}
	.isZero = zerochecker.Checker(.Type)

	if ,  := .Options["alias"];  {
		, _ = tagparser.Unquote()
		.FieldsMap[] = 
	}

	.allFields = append(.allFields, )
	if  {
		.skippedFields = append(.skippedFields, )
		.FieldsMap[.SQLName] = 
		return nil
	}

	if ,  := .Options["soft_delete"];  {
		.SetSoftDeleteField = setSoftDeleteFieldFunc(.Type)
		if .SetSoftDeleteField == nil {
			 := fmt.Errorf(
				"pg: soft_delete is only supported for time.Time, pg.NullTime, sql.NullInt64, and int64 (or implement ValueScanner that scans time)")
			panic()
		}
		.SoftDeleteField = 
	}

	return 
}

func ( *Table) () {
	.Methods = make(map[string]*Method)
	 := reflect.PtrTo(.Type)
	for  := 0;  < .NumMethod(); ++ {
		 := .Method()
		if .PkgPath != "" {
			continue
		}
		if .Type.NumIn() > 1 {
			continue
		}
		if .Type.NumOut() != 1 {
			continue
		}

		 := .Type.Out(0)
		.Methods[.Name] = &Method{
			Index: .Index,

			appender: types.Appender(),
		}
	}
}

func ( *Table) () {
	for ,  := range .skippedFields {
		if .Type.Kind() == reflect.Struct {
			.inlineFields(, nil)
		}
	}
}

func ( *Table) () {
	for  := 0;  < len(.Fields); {
		 := .Fields[]
		if .tryRelation() {
			.Fields = removeField(.Fields, )
			.DataFields = removeField(.DataFields, )
		} else {
			++
		}

		if .Type.Kind() == reflect.Struct {
			.inlineFields(, nil)
		}
	}
}

func ( *Table) ( *Field) bool {
	 := tagparser.Parse(.Field.Tag.Get("pg"))

	if ,  := .Options["rel"];  {
		return .tryRelationType(, , )
	}
	if ,  := .Options["many2many"];  {
		return .tryRelationType(, "many2many", )
	}

	if .UserSQLType != "" || isScanner(.Type) {
		return false
	}

	switch .Type.Kind() {
	case reflect.Slice:
		return .tryRelationSlice(, )
	case reflect.Struct:
		return .tryRelationStruct(, )
	}
	return false
}

func ( *Table) ( *Field,  string,  *tagparser.Tag) bool {
	switch  {
	case "has-one":
		return .mustHasOneRelation(, )
	case "belongs-to":
		return .mustBelongsToRelation(, )
	case "has-many":
		return .mustHasManyRelation(, )
	case "many2many":
		return .mustM2MRelation(, )
	default:
		panic(fmt.Errorf("pg: unknown relation=%s on field=%s", , .GoName))
	}
}

func ( *Table) ( *Field,  *tagparser.Tag) bool {
	 := _tables.get(.Type, true)
	 := .PKs

	,  := .Options["join_fk"]

	if  := .checkPKs();  != nil && ! {
		// join performed by primary key if join_fk not specified
		// so join table must have primary key
		panic()
	}

	if  {
		 := .getField()
		if  == nil {
			panic(fmt.Errorf(
				"pg: %s has-one %s: field %s specified by join_fk doesn't exist on %s",
				.TypeName, .GoName, , .TypeName,
			))
		}

		 = []*Field{}
	}

	,  := .Options["fk"]

	if  && len() == 1 {
		 := .getField()
		if  == nil {
			panic(fmt.Errorf(
				"pg: %s has-one %s: %s must have column %s "+
					"(use fk:custom_column tag on %s field to specify custom column)",
				.TypeName, .GoName, .TypeName, , .GoName,
			))
		}

		.addRelation(&Relation{
			Type:      HasOneRelation,
			Field:     ,
			JoinTable: ,
			BaseFKs:   []*Field{},
			JoinFKs:   ,
		})
		return true
	}

	if ! {
		 = internal.Underscore(.GoName) + "_"
	}
	 := make([]*Field, 0, len())

	for ,  := range  {
		 :=  + .SQLName
		if  := .getField();  != nil {
			 = append(, )
			continue
		}

		if  := .getField(.SQLName);  != nil {
			 = append(, )
			continue
		}

		panic(fmt.Errorf(
			"pg: %s has-one %s: %s must have column %s "+
				"(use fk:custom_column tag on %s field to specify custom column)",
			.TypeName, .GoName, .TypeName, , .GoName,
		))
	}

	.addRelation(&Relation{
		Type:      HasOneRelation,
		Field:     ,
		JoinTable: ,
		BaseFKs:   ,
		JoinFKs:   ,
	})
	return true
}

func ( *Table) ( *Field,  *tagparser.Tag) bool {
	if  := .checkPKs();  != nil {
		panic()
	}
	 := _tables.get(.Type, true)
	,  := .Options["join_fk"]

	if  && len(.PKs) == 1 {
		 := .getField()
		if  == nil {
			panic(fmt.Errorf(
				"pg: %s belongs-to %s: %s must have column %s "+
					"(use join_fk:custom_column tag on %s field to specify custom column)",
				.GoName, .TypeName, .TypeName, , .GoName,
			))
		}

		.addRelation(&Relation{
			Type:      BelongsToRelation,
			Field:     ,
			JoinTable: ,
			BaseFKs:   .PKs,
			JoinFKs:   []*Field{},
		})
		return true
	}

	if ! {
		 = internal.Underscore(.ModelName) + "_"
	}
	 := make([]*Field, 0, len(.PKs))

	for ,  := range .PKs {
		 :=  + .SQLName
		if  := .getField();  != nil {
			 = append(, )
			continue
		}

		if  := .getField(.SQLName);  != nil {
			 = append(, )
			continue
		}

		panic(fmt.Errorf(
			"pg: %s belongs-to %s: %s must have column %s "+
				"(use join_fk:custom_column tag on %s field to specify custom column)",
			.GoName, .TypeName, .TypeName, , .GoName,
		))
	}

	.addRelation(&Relation{
		Type:      BelongsToRelation,
		Field:     ,
		JoinTable: ,
		BaseFKs:   .PKs,
		JoinFKs:   ,
	})
	return true
}

func ( *Table) ( *Field,  *tagparser.Tag) bool {
	if  := .checkPKs();  != nil {
		panic()
	}
	if .Type.Kind() != reflect.Slice {
		panic(fmt.Errorf(
			"pg: %s.%s has-many relation requires slice, got %q",
			.TypeName, .GoName, .Type.Kind(),
		))
	}

	 := _tables.get(indirectType(.Type.Elem()), true)
	,  := .Options["join_fk"]
	,  := .Options["polymorphic"]

	if  && ! && len(.PKs) == 1 {
		 := .getField()
		if  == nil {
			panic(fmt.Errorf(
				"pg: %s has-many %s: %s must have column %s "+
					"(use join_fk:custom_column tag on %s field to specify custom column)",
				.TypeName, .GoName, .TypeName, , .GoName,
			))
		}

		.addRelation(&Relation{
			Type:      HasManyRelation,
			Field:     ,
			JoinTable: ,
			BaseFKs:   .PKs,
			JoinFKs:   []*Field{},
		})
		return true
	}

	if ! {
		 = internal.Underscore(.ModelName) + "_"
	}
	 := make([]*Field, 0, len(.PKs))

	for ,  := range .PKs {
		 :=  + .SQLName
		if  := .getField();  != nil {
			 = append(, )
			continue
		}

		if  := .getField(.SQLName);  != nil {
			 = append(, )
			continue
		}

		panic(fmt.Errorf(
			"pg: %s has-many %s: %s must have column %s "+
				"(use join_fk:custom_column tag on %s field to specify custom column)",
			.TypeName, .GoName, .TypeName, , .GoName,
		))
	}

	var  *Field

	if  {
		 :=  + "type"
		 = .getField()
		if  == nil {
			panic(fmt.Errorf(
				"pg: %s has-many %s: %s must have polymorphic column %s",
				.TypeName, .GoName, .TypeName, ,
			))
		}
	}

	.addRelation(&Relation{
		Type:        HasManyRelation,
		Field:       ,
		JoinTable:   ,
		BaseFKs:     .PKs,
		JoinFKs:     ,
		Polymorphic: ,
	})
	return true
}

func ( *Table) ( *Field,  *tagparser.Tag) bool {
	if .Type.Kind() != reflect.Slice {
		panic(fmt.Errorf(
			"pg: %s.%s many2many relation requires slice, got %q",
			.TypeName, .GoName, .Type.Kind(),
		))
	}
	 := _tables.get(indirectType(.Type.Elem()), true)

	if  := .checkPKs();  != nil {
		panic()
	}
	if  := .checkPKs();  != nil {
		panic()
	}

	,  := .Options["many2many"]
	if ! {
		panic(fmt.Errorf("pg: %s must have many2many tag option", .GoName))
	}
	 := quoteTableName()

	 := _tables.getByName()
	if  == nil {
		panic(fmt.Errorf(
			"pg: can't find %s table (use orm.RegisterTable to register the model)",
			,
		))
	}

	var  []string
	var  []string

	{
		,  := .Options["fk"]
		if ! {
			 = internal.Underscore(.ModelName) + "_"
		}

		if  && len(.PKs) == 1 {
			if .getField() == nil {
				panic(fmt.Errorf(
					"pg: %s many2many %s: %s must have column %s "+
						"(use fk:custom_column tag on %s field to specify custom column)",
					.TypeName, .GoName, .TypeName, , .GoName,
				))
			}
			 = []string{}
		} else {
			for ,  := range .PKs {
				 :=  + .SQLName
				if .getField() != nil {
					 = append(, )
					continue
				}

				if .getField(.SQLName) != nil {
					 = append(, .SQLName)
					continue
				}

				panic(fmt.Errorf(
					"pg: %s many2many %s: %s must have column %s "+
						"(use fk:custom_column tag on %s field to specify custom column)",
					.TypeName, .GoName, .TypeName, , .GoName,
				))
			}
		}
	}

	{
		,  := .Options["join_fk"]
		if ! {
			 = internal.Underscore(.ModelName) + "_"
		}

		if  && len(.PKs) == 1 {
			if .getField() == nil {
				panic(fmt.Errorf(
					"pg: %s many2many %s: %s must have column %s "+
						"(use join_fk:custom_column tag on %s field to specify custom column)",
					.TypeName, .GoName, .TypeName, , .GoName,
				))
			}
			 = []string{}
		} else {
			for ,  := range .PKs {
				 :=  + .SQLName
				if .getField() != nil {
					 = append(, )
					continue
				}

				if .getField(.SQLName) != nil {
					 = append(, .SQLName)
					continue
				}

				panic(fmt.Errorf(
					"pg: %s many2many %s: %s must have column %s "+
						"(use join_fk:custom_column tag on %s field to specify custom column)",
					.TypeName, .GoName, .TypeName, , .GoName,
				))
			}
		}
	}

	.addRelation(&Relation{
		Type:          Many2ManyRelation,
		Field:         ,
		JoinTable:     ,
		M2MTableName:  ,
		M2MTableAlias: .Alias,
		M2MBaseFKs:    ,
		M2MJoinFKs:    ,
	})
	return true
}

//nolint
func ( *Table) ( *Field,  *tagparser.Tag) bool {
	if .tryM2MRelation(, ) {
		internal.Deprecated.Printf(
			`add pg:"rel:many2many" to %s.%s field tag`, .TypeName, .GoName)
		return true
	}
	if .tryHasManyRelation(, ) {
		internal.Deprecated.Printf(
			`add pg:"rel:has-many" to %s.%s field tag`, .TypeName, .GoName)
		return true
	}
	return false
}

func ( *Table) ( *Field,  *tagparser.Tag) bool {
	 := indirectType(.Type.Elem())
	if .Kind() != reflect.Struct {
		return false
	}

	 := _tables.get(, true)

	,  := .Options["fk"]
	if  {
		if  == "-" {
			return false
		}
		 = tryUnderscorePrefix()
	}

	 := .Options["many2many"]
	if  == "" {
		return false
	}

	 := _tables.getByName(quoteIdent())

	var  types.Safe
	if  != nil {
		 = .Alias
	} else if  := strings.IndexByte(, '.');  >= 0 {
		 = quoteIdent([+1:])
	} else {
		 = quoteIdent()
	}

	var  []string
	if ! {
		 = .ModelName + "_"
	}
	if  != nil {
		 := foreignKeys(, , , )
		if len() == 0 {
			return false
		}
		for ,  := range  {
			 = append(, .SQLName)
		}
	} else {
		if  && len(.PKs) == 1 {
			 = append(, )
		} else {
			for ,  := range .PKs {
				 = append(, +.SQLName)
			}
		}
	}

	,  := .Options["join_fk"]
	if ! {
		,  = .Options["joinFK"]
		if  {
			internal.Deprecated.Printf("joinFK is renamed to join_fk")
		}
	}
	if  {
		 = tryUnderscorePrefix()
	} else {
		 = .ModelName + "_"
	}

	var  []string
	if  != nil {
		 := foreignKeys(, , , )
		if len() == 0 {
			return false
		}
		for ,  := range  {
			 = append(, .SQLName)
		}
	} else {
		if  && len(.PKs) == 1 {
			 = append(, )
		} else {
			for ,  := range .PKs {
				 = append(, +.SQLName)
			}
		}
	}

	.addRelation(&Relation{
		Type:          Many2ManyRelation,
		Field:         ,
		JoinTable:     ,
		M2MTableName:  quoteIdent(),
		M2MTableAlias: ,
		M2MBaseFKs:    ,
		M2MJoinFKs:    ,
	})
	return true
}

func ( *Table) ( *Field,  *tagparser.Tag) bool {
	 := indirectType(.Type.Elem())
	if .Kind() != reflect.Struct {
		return false
	}

	 := _tables.get(, true)

	,  := .Options["fk"]
	if  {
		if  == "-" {
			return false
		}
		 = tryUnderscorePrefix()
	}

	,  := .Options["polymorphic"]
	var  *Field
	if  {
		 = tryUnderscorePrefix()

		 = .getField( + "type")
		if  == nil {
			return false
		}
	} else if ! {
		 = .ModelName + "_"
	}

	 := foreignKeys(, , ,  || )
	if len() == 0 {
		return false
	}

	var  []*Field
	,  := .Options["fk_value"]
	if  {
		if len() > 1 {
			panic(fmt.Errorf("got fk_value, but there are %d fks", len()))
		}

		 := .getField()
		if  == nil {
			panic(fmt.Errorf("fk_value=%q not found in %s", , ))
		}
		 = append(, )
	} else {
		 = .PKs
	}

	if len() != len() {
		panic("len(fks) != len(fkValues)")
	}

	if len() > 0 {
		.addRelation(&Relation{
			Type:        HasManyRelation,
			Field:       ,
			JoinTable:   ,
			BaseFKs:     ,
			JoinFKs:     ,
			Polymorphic: ,
		})
		return true
	}

	return false
}

func ( *Table) ( *Field,  *tagparser.Tag) bool {
	 := _tables.get(.Type, true)

	if len(.allFields) == 0 {
		return false
	}

	if .tryHasOne(, , ) {
		internal.Deprecated.Printf(
			`add pg:"rel:has-one" to %s.%s field tag`, .TypeName, .GoName)
		.inlineFields(, nil)
		return true
	}

	if .tryBelongsToOne(, , ) {
		internal.Deprecated.Printf(
			`add pg:"rel:belongs-to" to %s.%s field tag`, .TypeName, .GoName)
		.inlineFields(, nil)
		return true
	}

	.inlineFields(, nil)
	return false
}

func ( *Table) ( *Field,  map[reflect.Type]struct{}) {
	if  == nil {
		 = map[reflect.Type]struct{}{
			.Type: {},
		}
	}

	if ,  := [.Type];  {
		return
	}
	[.Type] = struct{}{}

	 := _tables.get(.Type, true)
	for ,  := range .allFields {
		 = .Clone()
		.GoName = .GoName + "_" + .GoName
		.SQLName = .SQLName + "__" + .SQLName
		.Column = quoteIdent(.SQLName)
		.Index = appendNew(.Index, .Index...)

		.fieldsMapMu.Lock()
		if ,  := .FieldsMap[.SQLName]; ! {
			.FieldsMap[.SQLName] = 
		}
		.fieldsMapMu.Unlock()

		if .Type.Kind() != reflect.Struct {
			continue
		}

		if ,  := [.Type]; ! {
			.(, )
		}
	}
}

func ( []int,  ...int) []int {
	 := make([]int, len()+len())
	copy(, )
	copy([len():], )
	return 
}

func ( reflect.Type) bool {
	return .Implements(scannerType) || reflect.PtrTo().Implements(scannerType)
}

func ( *Field,  *tagparser.Tag) string {
	if ,  := .Options["type"];  {
		, _ = tagparser.Unquote()
		.UserSQLType = 
		 = normalizeSQLType()
		return 
	}

	if ,  := .Options["composite"];  {
		, _ = tagparser.Unquote()
		return 
	}

	if ,  := .Options["hstore"];  {
		return "hstore"
	} else if ,  := .Options["hstore"];  {
		return "hstore"
	}

	if .hasFlag(ArrayFlag) {
		switch .Type.Kind() {
		case reflect.Slice, reflect.Array:
			 := sqlType(.Type.Elem())
			return  + "[]"
		}
	}

	 := sqlType(.Type)
	return 
}

func ( reflect.Type) string {
	switch  {
	case timeType, nullTimeType, sqlNullTimeType:
		return pgTypeTimestampTz
	case ipType:
		return pgTypeInet
	case ipNetType:
		return pgTypeCidr
	case nullBoolType:
		return pgTypeBoolean
	case nullFloatType:
		return pgTypeDoublePrecision
	case nullIntType:
		return pgTypeBigint
	case nullStringType:
		return pgTypeText
	case jsonRawMessageType:
		return pgTypeJSONB
	}

	switch .Kind() {
	case reflect.Int8, reflect.Uint8, reflect.Int16:
		return pgTypeSmallint
	case reflect.Uint16, reflect.Int32:
		return pgTypeInteger
	case reflect.Uint32, reflect.Int64, reflect.Int:
		return pgTypeBigint
	case reflect.Uint, reflect.Uint64:
		// Unsigned bigint is not supported - use bigint.
		return pgTypeBigint
	case reflect.Float32:
		return pgTypeReal
	case reflect.Float64:
		return pgTypeDoublePrecision
	case reflect.Bool:
		return pgTypeBoolean
	case reflect.String:
		return pgTypeText
	case reflect.Map, reflect.Struct:
		return pgTypeJSONB
	case reflect.Array, reflect.Slice:
		if .Elem().Kind() == reflect.Uint8 {
			return pgTypeBytea
		}
		return pgTypeJSONB
	default:
		return .Kind().String()
	}
}

func ( string) string {
	switch  {
	case "int2":
		return pgTypeSmallint
	case "int4", "int", "serial":
		return pgTypeInteger
	case "int8", pgTypeBigserial:
		return pgTypeBigint
	case "float4":
		return pgTypeReal
	case "float8":
		return pgTypeDoublePrecision
	}
	return 
}

func (,  string) bool {
	return  == 
}

func ( *Table) ( *Table,  *Field,  *tagparser.Tag) bool {
	,  := .Options["fk"]
	if  {
		if  == "-" {
			return false
		}
		 = tryUnderscorePrefix()
	} else {
		 = internal.Underscore(.GoName) + "_"
	}

	 := foreignKeys(, , , )
	if len() > 0 {
		.addRelation(&Relation{
			Type:      HasOneRelation,
			Field:     ,
			JoinTable: ,
			BaseFKs:   ,
			JoinFKs:   .PKs,
		})
		return true
	}
	return false
}

func ( *Table) ( *Table,  *Field,  *tagparser.Tag) bool {
	,  := .Options["fk"]
	if  {
		if  == "-" {
			return false
		}
		 = tryUnderscorePrefix()
	} else {
		 = internal.Underscore(.TypeName) + "_"
	}

	 := foreignKeys(, , , )
	if len() > 0 {
		.addRelation(&Relation{
			Type:      BelongsToRelation,
			Field:     ,
			JoinTable: ,
			BaseFKs:   .PKs,
			JoinFKs:   ,
		})
		return true
	}
	return false
}

func ( *Table) ( *Relation) {
	if .Relations == nil {
		.Relations = make(map[string]*Relation)
	}
	,  := .Relations[.Field.GoName]
	if  {
		panic(fmt.Errorf("%s already has %s", , ))
	}
	.Relations[.Field.GoName] = 
}

func (,  *Table,  string,  bool) []*Field {
	var  []*Field

	for ,  := range .PKs {
		 :=  + .SQLName
		 := .getField()
		if  != nil && sqlTypeEqual(.SQLType, .SQLType) {
			 = append(, )
			continue
		}

		if strings.IndexByte(.SQLName, '_') == -1 {
			continue
		}

		 = .getField(.SQLName)
		if  != nil && sqlTypeEqual(.SQLType, .SQLType) {
			 = append(, )
			continue
		}
	}
	if len() > 0 && len() == len(.PKs) {
		return 
	}

	 = nil
	for ,  := range .PKs {
		if !strings.HasPrefix(.SQLName, "pk_") {
			continue
		}
		 := "fk_" + .SQLName[3:]
		 := .getField()
		if  != nil && sqlTypeEqual(.SQLType, .SQLType) {
			 = append(, )
		}
	}
	if len() > 0 && len() == len(.PKs) {
		return 
	}

	if  == "" || len(.PKs) != 1 {
		return nil
	}

	if  {
		 := .getField()
		if  != nil && sqlTypeEqual(.PKs[0].SQLType, .SQLType) {
			return []*Field{}
		}
	}

	for ,  := range []string{"id", "uuid"} {
		 := .getField( + )
		if  != nil && sqlTypeEqual(.PKs[0].SQLType, .SQLType) {
			return []*Field{}
		}
	}

	return nil
}

func ( reflect.Value,  types.Reader,  int) error {
	// Zero value so it works with SelectOrInsert.
	// TODO: better handle slices
	.Set(reflect.New(.Type()).Elem())

	if  == -1 {
		return nil
	}

	 := pgjson.NewDecoder()
	.UseNumber()
	return .Decode(.Addr().Interface())
}

func ( []byte,  reflect.Value,  int) []byte {
	return strconv.AppendInt(, int64(.Uint()), 10)
}

func ( []byte,  reflect.Value,  int) []byte {
	return strconv.AppendInt(, int64(.Elem().Uint()), 10)
}

func ( string) string {
	if  == "" {
		return 
	}
	if  := [0]; internal.IsUpper() {
		return internal.Underscore() + "_"
	}
	return 
}

func ( string) types.Safe {
	// Don't quote if table name contains placeholder (?) or parentheses.
	if strings.IndexByte(, '?') >= 0 ||
		strings.IndexByte(, '(') >= 0 && strings.IndexByte(, ')') >= 0 {
		return types.Safe()
	}
	return quoteIdent()
}

func ( string) types.Safe {
	return types.Safe(types.AppendIdent(nil, , 1))
}

func ( reflect.Type) func( reflect.Value) error {
	switch  {
	case timeType:
		return func( reflect.Value) error {
			 := .Addr().Interface().(*time.Time)
			* = time.Now()
			return nil
		}
	case nullTimeType:
		return func( reflect.Value) error {
			 := .Addr().Interface().(*types.NullTime)
			* = types.NullTime{Time: time.Now()}
			return nil
		}
	case nullIntType:
		return func( reflect.Value) error {
			 := .Addr().Interface().(*sql.NullInt64)
			* = sql.NullInt64{Int64: time.Now().UnixNano()}
			return nil
		}
	}

	switch .Kind() {
	case reflect.Int64:
		return func( reflect.Value) error {
			 := .Addr().Interface().(*int64)
			* = time.Now().UnixNano()
			return nil
		}
	case reflect.Ptr:
		break
	default:
		return setSoftDeleteFallbackFunc()
	}

	 := 
	 = .Elem()

	switch  { //nolint:gocritic
	case timeType:
		return func( reflect.Value) error {
			 := time.Now()
			.Set(reflect.ValueOf(&))
			return nil
		}
	}

	switch .Kind() { //nolint:gocritic
	case reflect.Int64:
		return func( reflect.Value) error {
			 := time.Now().UnixNano()
			.Set(reflect.ValueOf(&))
			return nil
		}
	}

	return setSoftDeleteFallbackFunc()
}

func ( reflect.Type) func( reflect.Value) error {
	 := types.Scanner()
	if  == nil {
		return nil
	}

	return func( reflect.Value) error {
		var  int
		 := types.AppendTime(nil, time.Now(), )
		return (, pool.NewBytesReader(), len())
	}
}

func ( string) bool {
	switch  {
	case "alias",
		"select",
		"tablespace",
		"partition_by",
		"discard_unknown_columns":
		return true
	}
	return false
}

func ( string) bool {
	switch  {
	case "alias",
		"type",
		"array",
		"hstore",
		"composite",
		"json_use_number",
		"msgpack",
		"notnull",
		"use_zero",
		"default",
		"unique",
		"soft_delete",
		"on_delete",
		"on_update",

		"pk",
		"nopk",
		"rel",
		"fk",
		"join_fk",
		"many2many",
		"polymorphic":
		return true
	}
	return false
}