package main

import (
	"fmt"
	"io"
	"os"

	"github.com/jmoiron/sqlx"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

type User struct {
	ID     int `gorm:"primaryKey"`
	Name   string
	Active bool
}

func run(w io.Writer) error {
	query, args, err := sqlx.Named("SELECT id FROM users WHERE active=:active AND id IN (:ids)", map[string]any{"active": true, "ids": []int{2, 7}})
	if err != nil {
		return err
	}
	query, args, err = sqlx.In(query, args...)
	if err != nil {
		return err
	}
	query = sqlx.Rebind(sqlx.DOLLAR, query)
	fmt.Fprintf(w, "sqlx: %s args=%v\n", query, args)
	_, _, emptyErr := sqlx.In("SELECT id FROM users WHERE id IN (?)", []int{})
	fmt.Fprintf(w, "sqlx: empty-slice-error=%t\n", emptyErr != nil)
	if emptyErr == nil {
		return fmt.Errorf("expected empty slice error")
	}

	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
	if err != nil {
		return err
	}
	raw, err := db.DB()
	if err != nil {
		return err
	}
	defer raw.Close()
	raw.SetMaxOpenConns(1)
	var version string
	if err := raw.QueryRow("SELECT sqlite_version()").Scan(&version); err != nil {
		return err
	}
	fmt.Fprintln(w, "SQLite:", version)
	if err := db.AutoMigrate(&User{}); err != nil {
		return err
	}
	if err := db.Create(&User{ID: 1, Name: "Ada", Active: true}).Error; err != nil {
		return err
	}

	result := db.Model(&User{}).Where("id = ?", 1).Updates(User{Active: false})
	if result.Error != nil {
		return result.Error
	}
	var got User
	if err := db.First(&got, 1).Error; err != nil {
		return err
	}
	fmt.Fprintf(w, "gorm struct: active=%t affected=%d\n", got.Active, result.RowsAffected)
	if !got.Active {
		return fmt.Errorf("struct unexpectedly updated zero value")
	}

	result = db.Model(&User{}).Where("id = ?", 1).Updates(map[string]any{"active": false})
	if result.Error != nil {
		return result.Error
	}
	got = User{}
	if err := db.First(&got, 1).Error; err != nil {
		return err
	}
	fmt.Fprintf(w, "gorm map: active=%t affected=%d\n", got.Active, result.RowsAffected)
	if got.Active {
		return fmt.Errorf("map did not update false")
	}

	stmt := db.Session(&gorm.Session{DryRun: true}).Model(&User{}).Where("id = ?", 1).Updates(map[string]any{"active": false})
	if stmt.Error != nil {
		return stmt.Error
	}
	fmt.Fprintf(w, "gorm SQL: %s vars=%v\n", stmt.Statement.SQL.String(), stmt.Statement.Vars)
	return nil
}

func main() {
	if err := run(os.Stdout); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
