github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/sys/uniques/utils.go (about)

     1  /*
     2   * Copyright (c) 2024-present unTill Software Development Group B.V.
     3   * @author Denis Gribanov
     4   */
     5  
     6  package uniques
     7  
     8  import (
     9  	"errors"
    10  	"fmt"
    11  
    12  	"github.com/voedger/voedger/pkg/appdef"
    13  	"github.com/voedger/voedger/pkg/istructs"
    14  	"github.com/voedger/voedger/pkg/istructsmem"
    15  )
    16  
    17  // returns ID of the record identified by the the provided unique combination
    18  // returns NullRecordID if there is no record by the provided unique combination or if the record is inactive
    19  func GetRecordIDByUniqueCombination(wsid istructs.WSID, tableQName appdef.QName, as istructs.IAppStructs, values map[string]interface{}) (istructs.RecordID, error) {
    20  	tableType := as.AppDef().Type(tableQName)
    21  	if tableType.Kind() == appdef.TypeKind_null {
    22  		return 0, appdef.ErrNotFound("type %q", tableQName)
    23  	}
    24  	table, ok := tableType.(appdef.IDoc) //nnv: why IDoc but not IRecord ??
    25  	if !ok {
    26  		return 0, fmt.Errorf("%q is not a table: %w", tableQName, appdef.ErrInvalidError)
    27  	}
    28  	// let's find the unique by set of field names
    29  	// matchedIUnique := appdef.IUnique(nil)
    30  	matchedUniqueQName := appdef.NullQName
    31  	matchedUniqueFields := []appdef.IField{}
    32  	for _, iUnique := range table.Uniques() {
    33  		if len(values) != len(iUnique.Fields()) {
    34  			continue
    35  		}
    36  		matchedFieldsCount := 0
    37  		for providedFieldName := range values {
    38  			for _, uniqueField := range iUnique.Fields() {
    39  				if uniqueField.Name() == providedFieldName {
    40  					matchedFieldsCount++
    41  					break
    42  				}
    43  			}
    44  		}
    45  		if matchedFieldsCount == len(iUnique.Fields()) {
    46  			matchedUniqueQName = iUnique.Name()
    47  			matchedUniqueFields = iUnique.Fields()
    48  			break
    49  		}
    50  	}
    51  	if matchedUniqueQName == appdef.NullQName && table.UniqueField() != nil && len(values) == 1 {
    52  		providedUniqueFieldName := ""
    53  		for n := range values {
    54  			providedUniqueFieldName = n
    55  		}
    56  		if table.UniqueField().Name() == providedUniqueFieldName {
    57  			matchedUniqueQName = table.QName()
    58  			matchedUniqueFields = append(matchedUniqueFields, table.UniqueField())
    59  		}
    60  	}
    61  	if matchedUniqueQName == appdef.NullQName {
    62  		return 0, fmt.Errorf("provided set of fields does not match any known unique of %s: %w", tableType.QName(), ErrUniqueNotExist)
    63  	}
    64  
    65  	// build unique field values stream
    66  	uniqueKeyValues, err := getUniqueKeyValuesFromMap(values, matchedUniqueFields, matchedUniqueQName)
    67  	if err != nil {
    68  		return 0, err
    69  	}
    70  
    71  	uniqueViewRecordBuilder := as.ViewRecords().KeyBuilder(qNameViewUniques)
    72  	buildUniqueViewKeyByValues(uniqueViewRecordBuilder, matchedUniqueQName, uniqueKeyValues)
    73  	uniqueViewRecord, err := as.ViewRecords().Get(wsid, uniqueViewRecordBuilder)
    74  	if err != nil {
    75  		if errors.Is(err, istructsmem.ErrRecordNotFound) {
    76  			return 0, nil
    77  		}
    78  		// notest
    79  		return 0, err
    80  	}
    81  	return uniqueViewRecord.AsRecordID(field_ID), nil
    82  }