-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodel.go
More file actions
144 lines (126 loc) · 4.49 KB
/
Copy pathmodel.go
File metadata and controls
144 lines (126 loc) · 4.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package thing
import (
"fmt"
"reflect"
"time"
)
// --- BaseModel Struct ---
// BaseModel provides common fields and functionality for database models.
// It should be embedded into specific model structs.
type BaseModel struct {
ID int64 `json:"id" db:"id,pk"` // Primary key (Added pk tag)
CreatedAt time.Time `json:"created_at" db:"created_at"` // Timestamp for creation
UpdatedAt time.Time `json:"updated_at" db:"updated_at"` // Timestamp for last update
Deleted bool `json:"deleted" db:"deleted"` // Soft delete flag
// --- Internal ORM state ---
// These fields should be populated by the ORM functions (ByID, Create, etc.).
// They are NOT saved to the DB or cache.
isNewRecord bool `json:"-" db:"-"` // Flag to indicate if the record is new
}
// --- BaseModel Methods ---
// GetID returns the primary key value.
func (b BaseModel) GetID() int64 {
return b.ID
}
// SetID sets the primary key value.
func (b *BaseModel) SetID(id int64) {
b.ID = id
}
// TableName returns the database table name for the model.
// Default implementation returns empty string, relying on getTableNameFromType.
// Override this method in your specific model struct for custom table names.
func (b BaseModel) TableName() string {
// Default implementation, getTableNameFromType will be used if this returns ""
return ""
}
// IsNewRecord returns whether this is a new record.
func (b *BaseModel) IsNewRecord() bool {
return b.isNewRecord
}
// KeepItem checks if the record is considered active (not soft-deleted).
func (b BaseModel) KeepItem() bool {
return !b.Deleted
}
// KeepItemFields returns the DB column names that the model's KeepItem() logic
// depends on (besides "deleted", which the framework already special-cases).
// When any of these columns changes, the framework invalidates the affected
// list/count query caches even if the column is absent from their WHERE clauses.
//
// The default implementation returns nil. A model that overrides KeepItem()
// MUST also override KeepItemFields() (returning nil if it depends on no mutable
// column); otherwise construction via New/Use fails fast.
func (b BaseModel) KeepItemFields() []string {
return nil
}
// SetNewRecordFlag sets the internal isNewRecord flag.
func (b *BaseModel) SetNewRecordFlag(isNew bool) {
b.isNewRecord = isNew
}
// --- Helper Functions --- (Moved GetBaseModelPtr back here)
// GetBaseModelPtr returns a pointer to the embedded BaseModel if it exists and is addressable.
func getBaseModelPtr(value interface{}) *BaseModel {
if value == nil {
return nil
}
val := reflect.ValueOf(value)
if val.Kind() == reflect.Pointer && val.IsNil() {
return nil
}
if val.Kind() == reflect.Pointer {
val = val.Elem()
}
if val.Kind() == reflect.Struct {
bmField := val.FieldByName("BaseModel")
if bmField.IsValid() && bmField.Type() == reflect.TypeOf(BaseModel{}) && bmField.CanAddr() {
return bmField.Addr().Interface().(*BaseModel)
}
}
return nil
}
// generateCacheKey creates a standard cache key string for a single model.
func generateCacheKey(tableName string, id int64) string {
// Format: {tableName}:{id}
return fmt.Sprintf("%s:%d", tableName, id)
}
// setNewRecordFlagIfBaseModel sets the flag if the value embeds BaseModel.
func setNewRecordFlagIfBaseModel(value interface{}, isNew bool) {
if bmPtr := getBaseModelPtr(value); bmPtr != nil {
bmPtr.SetNewRecordFlag(isNew)
}
}
// setCreatedAtTimestamp sets the CreatedAt field if it exists.
func setCreatedAtTimestamp(value interface{}, t time.Time) {
if bmPtr := getBaseModelPtr(value); bmPtr != nil {
bmPtr.CreatedAt = t
return
}
// Fallback for structs not embedding BaseModel but having CreatedAt
val := reflect.ValueOf(value)
if val.Kind() == reflect.Pointer {
val = val.Elem()
}
if val.Kind() == reflect.Struct {
field := val.FieldByName("CreatedAt")
if field.IsValid() && field.CanSet() && field.Type() == reflect.TypeOf(time.Time{}) {
field.Set(reflect.ValueOf(t))
}
}
}
// setUpdatedAtTimestamp sets the UpdatedAt field if it exists.
func setUpdatedAtTimestamp(value interface{}, t time.Time) {
if bmPtr := getBaseModelPtr(value); bmPtr != nil {
bmPtr.UpdatedAt = t
return
}
// Fallback for structs not embedding BaseModel but having UpdatedAt
val := reflect.ValueOf(value)
if val.Kind() == reflect.Pointer {
val = val.Elem()
}
if val.Kind() == reflect.Struct {
field := val.FieldByName("UpdatedAt")
if field.IsValid() && field.CanSet() && field.Type() == reflect.TypeOf(time.Time{}) {
field.Set(reflect.ValueOf(t))
}
}
}