@@ -1338,20 +1338,81 @@ export class RestApiHandler<Schema extends SchemaDef = SchemaDef> implements Api
13381338 return Object . values ( modelDef . fields ) . filter ( ( f ) => modelDef . idFields . includes ( f . name ) ) ;
13391339 }
13401340
1341- // map external ID name to unique constraint field
13421341 const externalIdName = this . externalIdMapping [ modelLower ] ;
1343- for ( const [ name , info ] of Object . entries ( modelDef . uniqueFields ) ) {
1344- if ( name === externalIdName ) {
1345- if ( typeof info . type === 'string' ) {
1346- // single unique field
1347- return [ this . requireField ( model , info . type ) ] ;
1348- } else {
1349- // compound unique fields
1350- return Object . keys ( info ) . map ( ( f ) => this . requireField ( model , f ) ) ;
1342+
1343+ // 1. Model-level @@unique(map: ...) (compound keys only)
1344+ if ( Array . isArray ( modelDef . attributes ) ) {
1345+ const uniqueAttr = modelDef . attributes . find (
1346+ ( attr : any ) =>
1347+ attr . name === '@@unique' &&
1348+ Array . isArray ( attr . args ) &&
1349+ attr . args . some ( ( a : any ) => a . name === 'map' && a . value ?. value === externalIdName ) ,
1350+ ) ;
1351+ if ( uniqueAttr ) {
1352+ const fieldsArg = uniqueAttr . args . find ( ( a : any ) => a . name === 'fields' ) ;
1353+ if ( fieldsArg && Array . isArray ( fieldsArg . value ?. items ) && fieldsArg . value . items . length >= 1 ) {
1354+ const fieldNames = fieldsArg . value . items . map ( ( item : any ) => {
1355+ let fieldName : string | undefined = undefined ;
1356+ if ( typeof item . field === 'string' && modelDef . fields [ item . field ] ) {
1357+ fieldName = item . field ;
1358+ } else if (
1359+ typeof item . value === 'object' &&
1360+ typeof item . value . name === 'string' &&
1361+ modelDef . fields [ item . value . name ]
1362+ ) {
1363+ fieldName = item . value . name ;
1364+ }
1365+ if ( ! fieldName ) {
1366+ throw new Error ( `Invalid unique field mapping in model ${ model } : ${ JSON . stringify ( item ) } ` ) ;
1367+ }
1368+ return fieldName ;
1369+ } ) ;
1370+ return fieldNames . map ( ( fieldName : string ) => this . requireField ( model , fieldName ) ) ;
13511371 }
13521372 }
13531373 }
13541374
1375+ // 2. uniqueFields by key name
1376+ const uniqueFieldEntry = Object . entries ( modelDef . uniqueFields ) . find ( ( [ name ] ) => name === externalIdName ) ;
1377+ if ( uniqueFieldEntry ) {
1378+ const [ name , info ] = uniqueFieldEntry ;
1379+ if ( typeof info . type === 'string' ) {
1380+ return [ this . requireField ( model , name ) ] ;
1381+ }
1382+ const fieldNames = Object . keys ( info ) . filter ( ( f ) => {
1383+ if ( ! ( f in modelDef . fields ) ) {
1384+ return false ;
1385+ }
1386+ const fieldInfo = ( info as Record < string , any > ) [ f ] ;
1387+ return typeof fieldInfo === 'object' && fieldInfo !== null && typeof fieldInfo . type === 'string' ;
1388+ } ) ;
1389+ if ( fieldNames . length === 0 ) {
1390+ throw new Error (
1391+ `No valid field names found for compound unique key ${ externalIdName } in model ${ model } ` ,
1392+ ) ;
1393+ }
1394+ return fieldNames . map ( ( f ) => this . requireField ( model , f ) ) ;
1395+ }
1396+
1397+
1398+ // 3. Field-level unique attribute with @unique(map: ...)
1399+ const field = Object . values ( modelDef . fields ) . find ( ( fieldDef ) => {
1400+ if ( ! Array . isArray ( fieldDef . attributes ) ) {
1401+ return false ;
1402+ }
1403+ // @unique (map: ...)
1404+ return fieldDef . attributes . some (
1405+ ( attr : any ) =>
1406+ attr . name === '@unique' &&
1407+ Array . isArray ( attr . args ) &&
1408+ attr . args . some ( ( a : any ) => a . name === 'map' && a . value ?. value === externalIdName ) ,
1409+ ) ;
1410+ } ) ;
1411+
1412+ if ( field ) {
1413+ return [ field ] ;
1414+ }
1415+
13551416 throw new Error ( `Model ${ model } does not have unique key ${ externalIdName } ` ) ;
13561417 }
13571418
@@ -2060,9 +2121,7 @@ export class RestApiHandler<Schema extends SchemaDef = SchemaDef> implements Api
20602121 }
20612122 } else {
20622123 if ( op === 'between' ) {
2063- const parts = value
2064- . split ( ',' )
2065- . map ( ( v ) => this . coerce ( fieldDef , v ) ) ;
2124+ const parts = value . split ( ',' ) . map ( ( v ) => this . coerce ( fieldDef , v ) ) ;
20662125 if ( parts . length !== 2 ) {
20672126 throw new InvalidValueError ( `"between" expects exactly 2 comma-separated values` ) ;
20682127 }
0 commit comments