// internal/database/connection_pool.gopackagedatabaseimport("context""database/sql""fmt""sync""time")// ConnectionPool represents a database connection pooltypeConnectionPoolstruct{db*sql.DBconfigPoolConfigmutexsync.RWMutexstatsPoolStats}// PoolConfig represents connection pool configurationtypePoolConfigstruct{MaxOpenConnsint`json:"max_open_conns"`MaxIdleConnsint`json:"max_idle_conns"`ConnMaxLifetimetime.Duration`json:"conn_max_lifetime"`ConnMaxIdleTimetime.Duration`json:"conn_max_idle_time"`PingIntervaltime.Duration`json:"ping_interval"`}// PoolStats represents connection pool statisticstypePoolStatsstruct{OpenConnectionsint`json:"open_connections"`InUseint`json:"in_use"`Idleint`json:"idle"`WaitCountint64`json:"wait_count"`WaitDurationtime.Duration`json:"wait_duration"`MaxIdleClosedint64`json:"max_idle_closed"`MaxIdleTimeClosedint64`json:"max_idle_time_closed"`MaxLifetimeClosedint64`json:"max_lifetime_closed"`}// NewConnectionPool creates a new connection poolfuncNewConnectionPool(driver,dsnstring,configPoolConfig)(*ConnectionPool,error){db,err:=sql.Open(driver,dsn)iferr!=nil{returnnil,fmt.Errorf("failed to open database: %w",err)}// Configure connection pooldb.SetMaxOpenConns(config.MaxOpenConns)db.SetMaxIdleConns(config.MaxIdleConns)db.SetConnMaxLifetime(config.ConnMaxLifetime)db.SetConnMaxIdleTime(config.ConnMaxIdleTime)pool:=&ConnectionPool{db:db,config:config,}// Start health monitoringgopool.monitorHealth()returnpool,nil}// GetDB returns the database connectionfunc(cp*ConnectionPool)GetDB()*sql.DB{returncp.db}// Ping pings the databasefunc(cp*ConnectionPool)Ping(ctxcontext.Context)error{returncp.db.PingContext(ctx)}// Close closes the connection poolfunc(cp*ConnectionPool)Close()error{returncp.db.Close()}// GetStats returns connection pool statisticsfunc(cp*ConnectionPool)GetStats()PoolStats{cp.mutex.RLock()defercp.mutex.RUnlock()stats:=cp.db.Stats()returnPoolStats{OpenConnections:stats.OpenConnections,InUse:stats.InUse,Idle:stats.Idle,WaitCount:stats.WaitCount,WaitDuration:stats.WaitDuration,MaxIdleClosed:stats.MaxIdleClosed,MaxIdleTimeClosed:stats.MaxIdleTimeClosed,MaxLifetimeClosed:stats.MaxLifetimeClosed,}}// monitorHealth monitors the health of the connection poolfunc(cp*ConnectionPool)monitorHealth(){ticker:=time.NewTicker(cp.config.PingInterval)deferticker.Stop()forrangeticker.C{ctx,cancel:=context.WithTimeout(context.Background(),5*time.Second)iferr:=cp.db.PingContext(ctx);err!=nil{// Handle ping failure}cancel()}}// Execute executes a query with retry logicfunc(cp*ConnectionPool)Execute(ctxcontext.Context,querystring,args...interface{})(sql.Result,error){varresultsql.Resultvarerrerrorfori:=0;i<3;i++{result,err=cp.db.ExecContext(ctx,query,args...)iferr==nil{returnresult,nil}ifi<2{time.Sleep(time.Duration(i+1)*time.Second)}}returnnil,fmt.Errorf("failed to execute query after 3 attempts: %w",err)}// Query executes a query and returns rowsfunc(cp*ConnectionPool)Query(ctxcontext.Context,querystring,args...interface{})(*sql.Rows,error){returncp.db.QueryContext(ctx,query,args...)}// QueryRow executes a query and returns a single rowfunc(cp*ConnectionPool)QueryRow(ctxcontext.Context,querystring,args...interface{})*sql.Row{returncp.db.QueryRowContext(ctx,query,args...)}
// internal/database/prepared_statements.gopackagedatabaseimport("context""database/sql""fmt""sync")// PreparedStatementCache represents a prepared statement cachetypePreparedStatementCachestruct{db*sql.DBstatementsmap[string]*sql.Stmtmutexsync.RWMutex}// NewPreparedStatementCache creates a new prepared statement cachefuncNewPreparedStatementCache(db*sql.DB)*PreparedStatementCache{return&PreparedStatementCache{db:db,statements:make(map[string]*sql.Stmt),}}// Get gets a prepared statementfunc(psc*PreparedStatementCache)Get(ctxcontext.Context,querystring)(*sql.Stmt,error){psc.mutex.RLock()stmt,exists:=psc.statements[query]psc.mutex.RUnlock()ifexists{returnstmt,nil}psc.mutex.Lock()deferpsc.mutex.Unlock()// Double-check after acquiring write lockifstmt,exists:=psc.statements[query];exists{returnstmt,nil}stmt,err:=psc.db.PrepareContext(ctx,query)iferr!=nil{returnnil,fmt.Errorf("failed to prepare statement: %w",err)}psc.statements[query]=stmtreturnstmt,nil}// Execute executes a prepared statementfunc(psc*PreparedStatementCache)Execute(ctxcontext.Context,querystring,args...interface{})(sql.Result,error){stmt,err:=psc.Get(ctx,query)iferr!=nil{returnnil,err}returnstmt.ExecContext(ctx,args...)}// Query executes a prepared statement and returns rowsfunc(psc*PreparedStatementCache)Query(ctxcontext.Context,querystring,args...interface{})(*sql.Rows,error){stmt,err:=psc.Get(ctx,query)iferr!=nil{returnnil,err}returnstmt.QueryContext(ctx,args...)}// QueryRow executes a prepared statement and returns a single rowfunc(psc*PreparedStatementCache)QueryRow(ctxcontext.Context,querystring,args...interface{})*sql.Row{stmt,err:=psc.Get(ctx,query)iferr!=nil{returnnil,err}returnstmt.QueryRowContext(ctx,args...)}// Close closes all prepared statementsfunc(psc*PreparedStatementCache)Close()error{psc.mutex.Lock()deferpsc.mutex.Unlock()for_,stmt:=rangepsc.statements{iferr:=stmt.Close();err!=nil{returnerr}}psc.statements=make(map[string]*sql.Stmt)returnnil}
// internal/database/transaction_manager.gopackagedatabaseimport("context""database/sql""fmt""sync")// TransactionManager represents a transaction managertypeTransactionManagerstruct{db*sql.DB}// NewTransactionManager creates a new transaction managerfuncNewTransactionManager(db*sql.DB)*TransactionManager{return&TransactionManager{db:db}}// Transaction represents a database transactiontypeTransactionstruct{tx*sql.Txctxcontext.Contextmutexsync.RWMutexclosedbool}// NewTransaction creates a new transactionfunc(tm*TransactionManager)NewTransaction(ctxcontext.Context)(*Transaction,error){tx,err:=tm.db.BeginTx(ctx,nil)iferr!=nil{returnnil,fmt.Errorf("failed to begin transaction: %w",err)}return&Transaction{tx:tx,ctx:ctx,closed:false,},nil}// Execute executes a query within the transactionfunc(t*Transaction)Execute(querystring,args...interface{})(sql.Result,error){t.mutex.RLock()defert.mutex.RUnlock()ift.closed{returnnil,fmt.Errorf("transaction is closed")}returnt.tx.ExecContext(t.ctx,query,args...)}// Query executes a query within the transactionfunc(t*Transaction)Query(querystring,args...interface{})(*sql.Rows,error){t.mutex.RLock()defert.mutex.RUnlock()ift.closed{returnnil,fmt.Errorf("transaction is closed")}returnt.tx.QueryContext(t.ctx,query,args...)}// QueryRow executes a query within the transactionfunc(t*Transaction)QueryRow(querystring,args...interface{})*sql.Row{t.mutex.RLock()defert.mutex.RUnlock()ift.closed{returnnil}returnt.tx.QueryRowContext(t.ctx,query,args...)}// Commit commits the transactionfunc(t*Transaction)Commit()error{t.mutex.Lock()defert.mutex.Unlock()ift.closed{returnfmt.Errorf("transaction is already closed")}err:=t.tx.Commit()t.closed=truereturnerr}// Rollback rolls back the transactionfunc(t*Transaction)Rollback()error{t.mutex.Lock()defert.mutex.Unlock()ift.closed{returnnil}err:=t.tx.Rollback()t.closed=truereturnerr}// WithTransaction executes a function within a transactionfunc(tm*TransactionManager)WithTransaction(ctxcontext.Context,fnfunc(*Transaction)error)error{tx,err:=tm.NewTransaction(ctx)iferr!=nil{returnerr}deferfunc(){if!tx.closed{tx.Rollback()}}()iferr:=fn(tx);err!=nil{returnerr}returntx.Commit()}
// internal/database/optimistic_locking.gopackagedatabaseimport("context""database/sql""fmt""time")// OptimisticLock represents an optimistic locktypeOptimisticLockstruct{IDint64`json:"id"`Versionint64`json:"version"`UpdatedAttime.Time`json:"updated_at"`}// OptimisticLocking provides optimistic locking functionalitytypeOptimisticLockingstruct{db*sql.DB}// NewOptimisticLocking creates a new optimistic locking instancefuncNewOptimisticLocking(db*sql.DB)*OptimisticLocking{return&OptimisticLocking{db:db}}// UpdateWithOptimisticLock updates a record with optimistic lockingfunc(ol*OptimisticLocking)UpdateWithOptimisticLock(ctxcontext.Context,tablestring,idint64,currentVersionint64,updatesmap[string]interface{})error{// Build update queryquery:=fmt.Sprintf("UPDATE %s SET version = version + 1, updated_at = NOW()",table)args:=[]interface{}{}argIndex:=1forcolumn,value:=rangeupdates{query+=fmt.Sprintf(", %s = $%d",column,argIndex)args=append(args,value)argIndex++}query+=fmt.Sprintf(" WHERE id = $%d AND version = $%d",argIndex,argIndex+1)args=append(args,id,currentVersion)result,err:=ol.db.ExecContext(ctx,query,args...)iferr!=nil{returnfmt.Errorf("failed to update record: %w",err)}rowsAffected,err:=result.RowsAffected()iferr!=nil{returnfmt.Errorf("failed to get rows affected: %w",err)}ifrowsAffected==0{returnfmt.Errorf("record was modified by another process")}returnnil}// GetWithOptimisticLock gets a record with optimistic lockingfunc(ol*OptimisticLocking)GetWithOptimisticLock(ctxcontext.Context,tablestring,idint64)(*OptimisticLock,error){query:=fmt.Sprintf("SELECT id, version, updated_at FROM %s WHERE id = $1",table)varlockOptimisticLockerr:=ol.db.QueryRowContext(ctx,query,id).Scan(&lock.ID,&lock.Version,&lock.UpdatedAt,)iferr!=nil{iferr==sql.ErrNoRows{returnnil,fmt.Errorf("record not found")}returnnil,fmt.Errorf("failed to get record: %w",err)}return&lock,nil}
// internal/database/query_builder.gopackagedatabaseimport("context""database/sql""fmt""strings")// QueryBuilder represents a query buildertypeQueryBuilderstruct{tablestringcolumns[]stringwhere[]stringargs[]interface{}orderBy[]stringlimitintoffsetintjoins[]stringgroupBy[]stringhaving[]string}// NewQueryBuilder creates a new query builderfuncNewQueryBuilder(tablestring)*QueryBuilder{return&QueryBuilder{table:table,columns:[]string{"*"},where:make([]string,0),args:make([]interface{},0),orderBy:make([]string,0),joins:make([]string,0),groupBy:make([]string,0),having:make([]string,0),}}// Select sets the columns to selectfunc(qb*QueryBuilder)Select(columns...string)*QueryBuilder{qb.columns=columnsreturnqb}// Where adds a WHERE clausefunc(qb*QueryBuilder)Where(conditionstring,args...interface{})*QueryBuilder{qb.where=append(qb.where,condition)qb.args=append(qb.args,args...)returnqb}// Join adds a JOIN clausefunc(qb*QueryBuilder)Join(table,conditionstring)*QueryBuilder{qb.joins=append(qb.joins,fmt.Sprintf("JOIN %s ON %s",table,condition))returnqb}// LeftJoin adds a LEFT JOIN clausefunc(qb*QueryBuilder)LeftJoin(table,conditionstring)*QueryBuilder{qb.joins=append(qb.joins,fmt.Sprintf("LEFT JOIN %s ON %s",table,condition))returnqb}// OrderBy adds an ORDER BY clausefunc(qb*QueryBuilder)OrderBy(columnstring,directionstring)*QueryBuilder{qb.orderBy=append(qb.orderBy,fmt.Sprintf("%s %s",column,direction))returnqb}// GroupBy adds a GROUP BY clausefunc(qb*QueryBuilder)GroupBy(columns...string)*QueryBuilder{qb.groupBy=append(qb.groupBy,columns...)returnqb}// Having adds a HAVING clausefunc(qb*QueryBuilder)Having(conditionstring,args...interface{})*QueryBuilder{qb.having=append(qb.having,condition)qb.args=append(qb.args,args...)returnqb}// Limit sets the LIMITfunc(qb*QueryBuilder)Limit(limitint)*QueryBuilder{qb.limit=limitreturnqb}// Offset sets the OFFSETfunc(qb*QueryBuilder)Offset(offsetint)*QueryBuilder{qb.offset=offsetreturnqb}// Build builds the SELECT queryfunc(qb*QueryBuilder)Build()(string,[]interface{}){query:=fmt.Sprintf("SELECT %s FROM %s",strings.Join(qb.columns,", "),qb.table)iflen(qb.joins)>0{query+=" "+strings.Join(qb.joins," ")}iflen(qb.where)>0{query+=" WHERE "+strings.Join(qb.where," AND ")}iflen(qb.groupBy)>0{query+=" GROUP BY "+strings.Join(qb.groupBy,", ")}iflen(qb.having)>0{query+=" HAVING "+strings.Join(qb.having," AND ")}iflen(qb.orderBy)>0{query+=" ORDER BY "+strings.Join(qb.orderBy,", ")}ifqb.limit>0{query+=fmt.Sprintf(" LIMIT %d",qb.limit)}ifqb.offset>0{query+=fmt.Sprintf(" OFFSET %d",qb.offset)}returnquery,qb.args}// Execute executes the queryfunc(qb*QueryBuilder)Execute(ctxcontext.Context,db*sql.DB)(*sql.Rows,error){query,args:=qb.Build()returndb.QueryContext(ctx,query,args...)}// ExecuteRow executes the query and returns a single rowfunc(qb*QueryBuilder)ExecuteRow(ctxcontext.Context,db*sql.DB)*sql.Row{query,args:=qb.Build()returndb.QueryRowContext(ctx,query,args...)}
// internal/database/query_cache.gopackagedatabaseimport("context""crypto/md5""database/sql""encoding/hex""fmt""sync""time")// QueryCache represents a query cachetypeQueryCachestruct{cachemap[string]CacheEntrymutexsync.RWMutexttltime.DurationmaxSizeint}// CacheEntry represents a cache entrytypeCacheEntrystruct{Datainterface{}Timestamptime.TimeTTLtime.Duration}// NewQueryCache creates a new query cachefuncNewQueryCache(ttltime.Duration,maxSizeint)*QueryCache{cache:=&QueryCache{cache:make(map[string]CacheEntry),ttl:ttl,maxSize:maxSize,}// Start cleanup goroutinegocache.cleanup()returncache}// Get gets a value from the cachefunc(qc*QueryCache)Get(keystring)(interface{},bool){qc.mutex.RLock()deferqc.mutex.RUnlock()entry,exists:=qc.cache[key]if!exists{returnnil,false}iftime.Since(entry.Timestamp)>entry.TTL{returnnil,false}returnentry.Data,true}// Set sets a value in the cachefunc(qc*QueryCache)Set(keystring,valueinterface{},ttltime.Duration){qc.mutex.Lock()deferqc.mutex.Unlock()// Check if cache is fulliflen(qc.cache)>=qc.maxSize{qc.evictOldest()}qc.cache[key]=CacheEntry{Data:value,Timestamp:time.Now(),TTL:ttl,}}// evictOldest evicts the oldest entryfunc(qc*QueryCache)evictOldest(){varoldestKeystringvaroldestTimetime.Timeforkey,entry:=rangeqc.cache{ifoldestKey==""||entry.Timestamp.Before(oldestTime){oldestKey=keyoldestTime=entry.Timestamp}}ifoldestKey!=""{delete(qc.cache,oldestKey)}}// cleanup removes expired entriesfunc(qc*QueryCache)cleanup(){ticker:=time.NewTicker(5*time.Minute)deferticker.Stop()forrangeticker.C{qc.mutex.Lock()now:=time.Now()forkey,entry:=rangeqc.cache{ifnow.Sub(entry.Timestamp)>entry.TTL{delete(qc.cache,key)}}qc.mutex.Unlock()}}// CachedQuery executes a cached queryfunc(qc*QueryCache)CachedQuery(ctxcontext.Context,db*sql.DB,querystring,args...interface{})([]map[string]interface{},error){// Generate cache keykey:=qc.generateKey(query,args...)// Check cacheifcached,exists:=qc.Get(key);exists{returncached.([]map[string]interface{}),nil}// Execute queryrows,err:=db.QueryContext(ctx,query,args...)iferr!=nil{returnnil,err}deferrows.Close()// Convert to mapresult,err:=qc.rowsToMap(rows)iferr!=nil{returnnil,err}// Cache resultqc.Set(key,result,qc.ttl)returnresult,nil}// generateKey generates a cache keyfunc(qc*QueryCache)generateKey(querystring,args...interface{})string{data:=fmt.Sprintf("%s%v",query,args)hash:=md5.Sum([]byte(data))returnhex.EncodeToString(hash[:])}// rowsToMap converts rows to mapfunc(qc*QueryCache)rowsToMap(rows*sql.Rows)([]map[string]interface{},error){columns,err:=rows.Columns()iferr!=nil{returnnil,err}varresult[]map[string]interface{}forrows.Next(){values:=make([]interface{},len(columns))valuePtrs:=make([]interface{},len(columns))fori:=rangevalues{valuePtrs[i]=&values[i]}iferr:=rows.Scan(valuePtrs...);err!=nil{returnnil,err}row:=make(map[string]interface{})fori,col:=rangecolumns{row[col]=values[i]}result=append(result,row)}returnresult,nil}
// internal/database/migration_manager.gopackagedatabaseimport("context""database/sql""fmt""sort""time")// Migration represents a database migrationtypeMigrationstruct{Versionint`json:"version"`Namestring`json:"name"`UpSQLstring`json:"up_sql"`DownSQLstring`json:"down_sql"`CreatedAttime.Time`json:"created_at"`AppliedAt*time.Time`json:"applied_at,omitempty"`}// MigrationManager represents a migration managertypeMigrationManagerstruct{db*sql.DBmigrations[]Migration}// NewMigrationManager creates a new migration managerfuncNewMigrationManager(db*sql.DB)*MigrationManager{return&MigrationManager{db:db,migrations:make([]Migration,0),}}// AddMigration adds a migrationfunc(mm*MigrationManager)AddMigration(migrationMigration){mm.migrations=append(mm.migrations,migration)sort.Slice(mm.migrations,func(i,jint)bool{returnmm.migrations[i].Version<mm.migrations[j].Version})}// Migrate runs all pending migrationsfunc(mm*MigrationManager)Migrate(ctxcontext.Context)error{// Create migrations table if it doesn't existiferr:=mm.createMigrationsTable(ctx);err!=nil{returnfmt.Errorf("failed to create migrations table: %w",err)}// Get applied migrationsapplied,err:=mm.getAppliedMigrations(ctx)iferr!=nil{returnfmt.Errorf("failed to get applied migrations: %w",err)}// Run pending migrationsfor_,migration:=rangemm.migrations{if_,exists:=applied[migration.Version];!exists{iferr:=mm.runMigration(ctx,migration);err!=nil{returnfmt.Errorf("failed to run migration %d: %w",migration.Version,err)}}}returnnil}// Rollback rolls back the last migrationfunc(mm*MigrationManager)Rollback(ctxcontext.Context)error{// Get applied migrationsapplied,err:=mm.getAppliedMigrations(ctx)iferr!=nil{returnfmt.Errorf("failed to get applied migrations: %w",err)}// Find the last applied migrationvarlastMigration*Migrationfor_,migration:=rangemm.migrations{if_,exists:=applied[migration.Version];exists{lastMigration=&migration}}iflastMigration==nil{returnfmt.Errorf("no migrations to rollback")}// Rollback the migrationiferr:=mm.rollbackMigration(ctx,*lastMigration);err!=nil{returnfmt.Errorf("failed to rollback migration %d: %w",lastMigration.Version,err)}returnnil}// createMigrationsTable creates the migrations tablefunc(mm*MigrationManager)createMigrationsTable(ctxcontext.Context)error{query:=` CREATE TABLE IF NOT EXISTS migrations ( version INTEGER PRIMARY KEY, name VARCHAR(255) NOT NULL, applied_at TIMESTAMP NOT NULL DEFAULT NOW() ) `_,err:=mm.db.ExecContext(ctx,query)returnerr}// getAppliedMigrations gets applied migrationsfunc(mm*MigrationManager)getAppliedMigrations(ctxcontext.Context)(map[int]bool,error){query:="SELECT version FROM migrations ORDER BY version"rows,err:=mm.db.QueryContext(ctx,query)iferr!=nil{returnnil,err}deferrows.Close()applied:=make(map[int]bool)forrows.Next(){varversionintiferr:=rows.Scan(&version);err!=nil{returnnil,err}applied[version]=true}returnapplied,nil}// runMigration runs a migrationfunc(mm*MigrationManager)runMigration(ctxcontext.Context,migrationMigration)error{// Start transactiontx,err:=mm.db.BeginTx(ctx,nil)iferr!=nil{returnerr}defertx.Rollback()// Run migration SQLif_,err:=tx.ExecContext(ctx,migration.UpSQL);err!=nil{returnerr}// Record migrationquery:="INSERT INTO migrations (version, name) VALUES ($1, $2)"if_,err:=tx.ExecContext(ctx,query,migration.Version,migration.Name);err!=nil{returnerr}// Commit transactionreturntx.Commit()}// rollbackMigration rolls back a migrationfunc(mm*MigrationManager)rollbackMigration(ctxcontext.Context,migrationMigration)error{// Start transactiontx,err:=mm.db.BeginTx(ctx,nil)iferr!=nil{returnerr}defertx.Rollback()// Run rollback SQLif_,err:=tx.ExecContext(ctx,migration.DownSQL);err!=nil{returnerr}// Remove migration recordquery:="DELETE FROM migrations WHERE version = $1"if_,err:=tx.ExecContext(ctx,query,migration.Version);err!=nil{returnerr}// Commit transactionreturntx.Commit()}
// internal/database/orm.gopackagedatabaseimport("context""database/sql""fmt""reflect""strings""time")// ORM represents a simple ORMtypeORMstruct{db*sql.DB}// NewORM creates a new ORMfuncNewORM(db*sql.DB)*ORM{return&ORM{db:db}}// Model represents a database modeltypeModelinterface{TableName()stringPrimaryKey()stringFields()map[string]interface{}SetFields(fieldsmap[string]interface{})}// User represents a user modeltypeUserstruct{IDint64`json:"id" db:"id"`Namestring`json:"name" db:"name"`Emailstring`json:"email" db:"email"`CreatedAttime.Time`json:"created_at" db:"created_at"`UpdatedAttime.Time`json:"updated_at" db:"updated_at"`}// TableName returns the table namefunc(u*User)TableName()string{return"users"}// PrimaryKey returns the primary key fieldfunc(u*User)PrimaryKey()string{return"id"}// Fields returns the model fieldsfunc(u*User)Fields()map[string]interface{}{returnmap[string]interface{}{"id":u.ID,"name":u.Name,"email":u.Email,"created_at":u.CreatedAt,"updated_at":u.UpdatedAt,}}// SetFields sets the model fieldsfunc(u*User)SetFields(fieldsmap[string]interface{}){ifid,ok:=fields["id"].(int64);ok{u.ID=id}ifname,ok:=fields["name"].(string);ok{u.Name=name}ifemail,ok:=fields["email"].(string);ok{u.Email=email}ifcreatedAt,ok:=fields["created_at"].(time.Time);ok{u.CreatedAt=createdAt}ifupdatedAt,ok:=fields["updated_at"].(time.Time);ok{u.UpdatedAt=updatedAt}}// Create creates a new recordfunc(orm*ORM)Create(ctxcontext.Context,modelModel)error{fields:=model.Fields()delete(fields,model.PrimaryKey())// Remove primary key for insertcolumns:=make([]string,0,len(fields))values:=make([]interface{},0,len(fields))placeholders:=make([]string,0,len(fields))forcolumn,value:=rangefields{columns=append(columns,column)values=append(values,value)placeholders=append(placeholders,"?")}query:=fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)",model.TableName(),strings.Join(columns,", "),strings.Join(placeholders,", "),)result,err:=orm.db.ExecContext(ctx,query,values...)iferr!=nil{returnerr}id,err:=result.LastInsertId()iferr!=nil{returnerr}// Set the ID on the modelfields[model.PrimaryKey()]=idmodel.SetFields(fields)returnnil}// Find finds a record by IDfunc(orm*ORM)Find(ctxcontext.Context,modelModel,idinterface{})error{query:=fmt.Sprintf("SELECT * FROM %s WHERE %s = ?",model.TableName(),model.PrimaryKey())row:=orm.db.QueryRowContext(ctx,query,id)// Get column namescolumns,err:=row.Columns()iferr!=nil{returnerr}// Create slice of pointersvalues:=make([]interface{},len(columns))valuePtrs:=make([]interface{},len(columns))fori:=rangevalues{valuePtrs[i]=&values[i]}// Scan the rowiferr:=row.Scan(valuePtrs...);err!=nil{returnerr}// Create fields mapfields:=make(map[string]interface{})fori,column:=rangecolumns{fields[column]=values[i]}model.SetFields(fields)returnnil}// Update updates a recordfunc(orm*ORM)Update(ctxcontext.Context,modelModel)error{fields:=model.Fields()id:=fields[model.PrimaryKey()]delete(fields,model.PrimaryKey())// Remove primary key from updatecolumns:=make([]string,0,len(fields))values:=make([]interface{},0,len(fields))forcolumn,value:=rangefields{columns=append(columns,fmt.Sprintf("%s = ?",column))values=append(values,value)}query:=fmt.Sprintf("UPDATE %s SET %s WHERE %s = ?",model.TableName(),strings.Join(columns,", "),model.PrimaryKey(),)values=append(values,id)_,err:=orm.db.ExecContext(ctx,query,values...)returnerr}// Delete deletes a recordfunc(orm*ORM)Delete(ctxcontext.Context,modelModel)error{fields:=model.Fields()id:=fields[model.PrimaryKey()]query:=fmt.Sprintf("DELETE FROM %s WHERE %s = ?",model.TableName(),model.PrimaryKey())_,err:=orm.db.ExecContext(ctx,query,id)returnerr}