github.com/gogf/gf@v1.16.9/database/gdb/gdb_model_time.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gdb
     8  
     9  import (
    10  	"fmt"
    11  	"github.com/gogf/gf/container/garray"
    12  	"github.com/gogf/gf/text/gregex"
    13  	"github.com/gogf/gf/text/gstr"
    14  	"github.com/gogf/gf/util/gconv"
    15  	"github.com/gogf/gf/util/gutil"
    16  )
    17  
    18  var (
    19  	createdFiledNames = []string{"created_at", "create_at"} // Default filed names of table for automatic-filled created datetime.
    20  	updatedFiledNames = []string{"updated_at", "update_at"} // Default filed names of table for automatic-filled updated datetime.
    21  	deletedFiledNames = []string{"deleted_at", "delete_at"} // Default filed names of table for automatic-filled deleted datetime.
    22  )
    23  
    24  // Unscoped disables the auto-update time feature for insert, update and delete options.
    25  func (m *Model) Unscoped() *Model {
    26  	model := m.getModel()
    27  	model.unscoped = true
    28  	return model
    29  }
    30  
    31  // getSoftFieldNameCreate checks and returns the field name for record creating time.
    32  // If there's no field name for storing creating time, it returns an empty string.
    33  // It checks the key with or without cases or chars '-'/'_'/'.'/' '.
    34  func (m *Model) getSoftFieldNameCreated(table ...string) string {
    35  	// It checks whether this feature disabled.
    36  	if m.db.GetConfig().TimeMaintainDisabled {
    37  		return ""
    38  	}
    39  	tableName := ""
    40  	if len(table) > 0 {
    41  		tableName = table[0]
    42  	} else {
    43  		tableName = m.tablesInit
    44  	}
    45  	config := m.db.GetConfig()
    46  	if config.CreatedAt != "" {
    47  		return m.getSoftFieldName(tableName, []string{config.CreatedAt})
    48  	}
    49  	return m.getSoftFieldName(tableName, createdFiledNames)
    50  }
    51  
    52  // getSoftFieldNameUpdate checks and returns the field name for record updating time.
    53  // If there's no field name for storing updating time, it returns an empty string.
    54  // It checks the key with or without cases or chars '-'/'_'/'.'/' '.
    55  func (m *Model) getSoftFieldNameUpdated(table ...string) (field string) {
    56  	// It checks whether this feature disabled.
    57  	if m.db.GetConfig().TimeMaintainDisabled {
    58  		return ""
    59  	}
    60  	tableName := ""
    61  	if len(table) > 0 {
    62  		tableName = table[0]
    63  	} else {
    64  		tableName = m.tablesInit
    65  	}
    66  	config := m.db.GetConfig()
    67  	if config.UpdatedAt != "" {
    68  		return m.getSoftFieldName(tableName, []string{config.UpdatedAt})
    69  	}
    70  	return m.getSoftFieldName(tableName, updatedFiledNames)
    71  }
    72  
    73  // getSoftFieldNameDelete checks and returns the field name for record deleting time.
    74  // If there's no field name for storing deleting time, it returns an empty string.
    75  // It checks the key with or without cases or chars '-'/'_'/'.'/' '.
    76  func (m *Model) getSoftFieldNameDeleted(table ...string) (field string) {
    77  	// It checks whether this feature disabled.
    78  	if m.db.GetConfig().TimeMaintainDisabled {
    79  		return ""
    80  	}
    81  	tableName := ""
    82  	if len(table) > 0 {
    83  		tableName = table[0]
    84  	} else {
    85  		tableName = m.tablesInit
    86  	}
    87  	config := m.db.GetConfig()
    88  	if config.UpdatedAt != "" {
    89  		return m.getSoftFieldName(tableName, []string{config.DeletedAt})
    90  	}
    91  	return m.getSoftFieldName(tableName, deletedFiledNames)
    92  }
    93  
    94  // getSoftFieldName retrieves and returns the field name of the table for possible key.
    95  func (m *Model) getSoftFieldName(table string, keys []string) (field string) {
    96  	fieldsMap, _ := m.TableFields(table)
    97  	if len(fieldsMap) > 0 {
    98  		for _, key := range keys {
    99  			field, _ = gutil.MapPossibleItemByKey(
   100  				gconv.Map(fieldsMap), key,
   101  			)
   102  			if field != "" {
   103  				return
   104  			}
   105  		}
   106  	}
   107  	return
   108  }
   109  
   110  // getConditionForSoftDeleting retrieves and returns the condition string for soft deleting.
   111  // It supports multiple tables string like:
   112  // "user u, user_detail ud"
   113  // "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid)"
   114  // "user LEFT JOIN user_detail ON(user_detail.uid=user.uid)"
   115  // "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid) LEFT JOIN user_stats us ON(us.uid=u.uid)"
   116  func (m *Model) getConditionForSoftDeleting() string {
   117  	if m.unscoped {
   118  		return ""
   119  	}
   120  	conditionArray := garray.NewStrArray()
   121  	if gstr.Contains(m.tables, " JOIN ") {
   122  		// Base table.
   123  		match, _ := gregex.MatchString(`(.+?) [A-Z]+ JOIN`, m.tables)
   124  		conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(match[1]))
   125  		// Multiple joined tables, exclude the sub query sql which contains char '(' and ')'.
   126  		matches, _ := gregex.MatchAllString(`JOIN ([^()]+?) ON`, m.tables)
   127  		for _, match := range matches {
   128  			conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(match[1]))
   129  		}
   130  	}
   131  	if conditionArray.Len() == 0 && gstr.Contains(m.tables, ",") {
   132  		// Multiple base tables.
   133  		for _, s := range gstr.SplitAndTrim(m.tables, ",") {
   134  			conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(s))
   135  		}
   136  	}
   137  	conditionArray.FilterEmpty()
   138  	if conditionArray.Len() > 0 {
   139  		return conditionArray.Join(" AND ")
   140  	}
   141  	// Only one table.
   142  	if fieldName := m.getSoftFieldNameDeleted(); fieldName != "" {
   143  		return fmt.Sprintf(`%s IS NULL`, m.db.GetCore().QuoteWord(fieldName))
   144  	}
   145  	return ""
   146  }
   147  
   148  // getConditionOfTableStringForSoftDeleting does something as its name describes.
   149  func (m *Model) getConditionOfTableStringForSoftDeleting(s string) string {
   150  	var (
   151  		field  = ""
   152  		table  = ""
   153  		array1 = gstr.SplitAndTrim(s, " ")
   154  		array2 = gstr.SplitAndTrim(array1[0], ".")
   155  	)
   156  	if len(array2) >= 2 {
   157  		table = array2[1]
   158  	} else {
   159  		table = array2[0]
   160  	}
   161  	field = m.getSoftFieldNameDeleted(table)
   162  	if field == "" {
   163  		return ""
   164  	}
   165  	if len(array1) >= 3 {
   166  		return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(array1[2]), m.db.GetCore().QuoteWord(field))
   167  	}
   168  	if len(array1) >= 2 {
   169  		return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(array1[1]), m.db.GetCore().QuoteWord(field))
   170  	}
   171  	return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(table), m.db.GetCore().QuoteWord(field))
   172  }