@@ -60,12 +60,12 @@ import core, {
60
60
type WorkspaceId
61
61
} from '@hcengineering/core'
62
62
import {
63
+ calcHashHash ,
63
64
type DbAdapter ,
64
65
type DbAdapterHandler ,
65
66
type DomainHelperOperations ,
66
67
type ServerFindOptions ,
67
- type TxAdapter ,
68
- calcHashHash
68
+ type TxAdapter
69
69
} from '@hcengineering/server-core'
70
70
import type postgres from 'postgres'
71
71
import { createDBClient , createGreenDBClient , type DBClient } from './client'
@@ -1304,7 +1304,11 @@ abstract class PostgresAdapterBase implements DbAdapter {
1304
1304
private translateQueryValue ( vars : ValuesVariables , tkey : string , value : any , type : ValueType ) : string | undefined {
1305
1305
const tkeyData = tkey . includes ( 'data' ) && ( tkey . includes ( '->' ) || tkey . includes ( '#>>' ) )
1306
1306
if ( tkeyData && ( Array . isArray ( value ) || ( typeof value !== 'object' && typeof value !== 'string' ) ) ) {
1307
- value = Array . isArray ( value ) ? value . map ( ( it ) => ( it == null ? null : `${ it } ` ) ) : `${ value } `
1307
+ value = Array . isArray ( value )
1308
+ ? value . map ( ( it ) => ( it == null ? null : `${ it } ` ) )
1309
+ : value == null
1310
+ ? null
1311
+ : `${ value } `
1308
1312
}
1309
1313
1310
1314
if ( value === null ) {
@@ -1315,76 +1319,87 @@ abstract class PostgresAdapterBase implements DbAdapter {
1315
1319
for ( const operator in value ) {
1316
1320
let val = value [ operator ]
1317
1321
if ( tkeyData && ( Array . isArray ( val ) || ( typeof val !== 'object' && typeof val !== 'string' ) ) ) {
1318
- val = Array . isArray ( val ) ? val . map ( ( it ) => ( it == null ? null : `${ it } ` ) ) : `${ val } `
1322
+ val = Array . isArray ( val ) ? val . map ( ( it ) => ( it == null ? null : `${ it } ` ) ) : val == null ? null : `${ val } `
1319
1323
}
1324
+
1325
+ let valType = inferType ( val )
1326
+ const { tlkey, arrowCount } = prepareJsonValue ( tkey , valType )
1327
+ if ( arrowCount > 0 && valType === '::text' ) {
1328
+ valType = ''
1329
+ }
1330
+
1320
1331
switch ( operator ) {
1321
1332
case '$ne' :
1322
- if ( val === null ) {
1323
- res . push ( `${ tkey } IS NOT NULL` )
1333
+ if ( val == null ) {
1334
+ res . push ( `${ tlkey } IS NOT NULL` )
1324
1335
} else {
1325
- res . push ( `${ tkey } != ${ vars . add ( val , inferType ( val ) ) } ` )
1336
+ res . push ( `${ tlkey } != ${ vars . add ( val , valType ) } ` )
1326
1337
}
1327
1338
break
1328
1339
case '$gt' :
1329
- res . push ( `${ tkey } > ${ vars . add ( val , inferType ( val ) ) } ` )
1340
+ res . push ( `${ tlkey } > ${ vars . add ( val , valType ) } ` )
1330
1341
break
1331
1342
case '$gte' :
1332
- res . push ( `${ tkey } >= ${ vars . add ( val , inferType ( val ) ) } ` )
1343
+ res . push ( `${ tlkey } >= ${ vars . add ( val , valType ) } ` )
1333
1344
break
1334
1345
case '$lt' :
1335
- res . push ( `${ tkey } < ${ vars . add ( val , inferType ( val ) ) } ` )
1346
+ res . push ( `${ tlkey } < ${ vars . add ( val , valType ) } ` )
1336
1347
break
1337
1348
case '$lte' :
1338
- res . push ( `${ tkey } <= ${ vars . add ( val , inferType ( val ) ) } ` )
1349
+ res . push ( `${ tlkey } <= ${ vars . add ( val , valType ) } ` )
1339
1350
break
1340
1351
case '$in' :
1341
1352
switch ( type ) {
1342
1353
case 'common' :
1343
1354
if ( Array . isArray ( val ) && val . includes ( null ) ) {
1344
- const vv = vars . addArray ( val , inferType ( val ) )
1345
- res . push ( `(${ tkey } = ANY(${ vv } ) OR ${ tkey } IS NULL)` )
1355
+ const vv = vars . addArray ( val , valType )
1356
+ res . push ( `(${ tlkey } = ANY(${ vv } ) OR ${ tkey } IS NULL)` )
1346
1357
} else {
1347
1358
if ( val . length > 0 ) {
1348
- res . push ( `${ tkey } = ANY(${ vars . addArray ( val , inferType ( val ) ) } )` )
1359
+ res . push ( `${ tlkey } = ANY(${ vars . addArray ( val , valType ) } )` )
1349
1360
} else {
1350
- res . push ( `${ tkey } IN ('NULL')` )
1361
+ res . push ( `${ tlkey } IN ('NULL')` )
1351
1362
}
1352
1363
}
1353
1364
break
1354
1365
case 'array' :
1355
1366
{
1356
- const vv = vars . addArrayI ( val , inferType ( val ) )
1367
+ const vv = vars . addArrayI ( val , valType )
1357
1368
res . push ( `${ tkey } && ${ vv } ` )
1358
1369
}
1359
1370
break
1360
1371
case 'dataArray' :
1361
1372
{
1362
- const vv = vars . addArrayI ( val , inferType ( val ) )
1373
+ const vv = vars . addArrayI ( val , valType )
1363
1374
res . push ( `${ tkey } ?| ${ vv } ` )
1364
1375
}
1365
1376
break
1366
1377
}
1367
1378
break
1368
1379
case '$nin' :
1369
1380
if ( Array . isArray ( val ) && val . includes ( null ) ) {
1370
- res . push ( `(${ tkey } != ALL(${ vars . addArray ( val , inferType ( val ) ) } ) AND ${ tkey } IS NOT NULL)` )
1381
+ res . push ( `(${ tlkey } != ALL(${ vars . addArray ( val , valType ) } ) AND ${ tkey } IS NOT NULL)` )
1371
1382
} else if ( Array . isArray ( val ) && val . length > 0 ) {
1372
- res . push ( `${ tkey } != ALL(${ vars . addArray ( val , inferType ( val ) ) } )` )
1383
+ res . push ( `${ tlkey } != ALL(${ vars . addArray ( val , valType ) } )` )
1373
1384
}
1374
1385
break
1375
1386
case '$like' :
1376
- res . push ( `${ tkey } ILIKE ${ vars . add ( val , inferType ( val ) ) } ` )
1387
+ res . push ( `${ tlkey } ILIKE ${ vars . add ( val , valType ) } ` )
1377
1388
break
1378
1389
case '$exists' :
1379
- res . push ( `${ tkey } IS ${ val === true || val === 'true' ? 'NOT NULL' : 'NULL' } ` )
1390
+ res . push ( `${ tlkey } IS ${ val === true || val === 'true' ? 'NOT NULL' : 'NULL' } ` )
1380
1391
break
1381
1392
case '$regex' :
1382
- res . push ( `${ tkey } SIMILAR TO ${ vars . add ( val , inferType ( val ) ) } ` )
1393
+ res . push ( `${ tlkey } SIMILAR TO ${ vars . add ( val , valType ) } ` )
1383
1394
break
1384
1395
case '$options' :
1385
1396
break
1386
1397
case '$all' :
1387
- res . push ( `${ tkey } @> ${ vars . addArray ( value , inferType ( value ) ) } ` )
1398
+ if ( arrowCount > 0 ) {
1399
+ res . push ( `${ tkey } @> '${ JSON . stringify ( val ) } '::jsonb` )
1400
+ } else {
1401
+ res . push ( `${ tkey } @> ${ vars . addArray ( val , valType ) } ` )
1402
+ }
1388
1403
break
1389
1404
default :
1390
1405
res . push ( `${ tkey } @> '[${ JSON . stringify ( value ) } ]'` )
@@ -1394,8 +1409,13 @@ abstract class PostgresAdapterBase implements DbAdapter {
1394
1409
return res . length === 0 ? undefined : res . join ( ' AND ' )
1395
1410
}
1396
1411
1412
+ let valType = inferType ( value )
1413
+ const { tlkey, arrowCount } = prepareJsonValue ( tkey , valType )
1414
+ if ( arrowCount > 0 && valType === '::text' ) {
1415
+ valType = ''
1416
+ }
1397
1417
return type === 'common'
1398
- ? `${ tkey } = ${ vars . add ( value , inferType ( value ) ) } `
1418
+ ? `${ tlkey } = ${ vars . add ( value , valType ) } `
1399
1419
: type === 'array'
1400
1420
? `${ tkey } @> '${ typeof value === 'string' ? '{"' + value + '"}' : value } '`
1401
1421
: `${ tkey } @> '${ typeof value === 'string' ? '"' + value + '"' : value } '`
@@ -2093,6 +2113,21 @@ class PostgresTxAdapter extends PostgresAdapterBase implements TxAdapter {
2093
2113
return this . stripHash ( systemTx . concat ( userTx ) ) as Tx [ ]
2094
2114
}
2095
2115
}
2116
+ function prepareJsonValue ( tkey : string , valType : string ) : { tlkey : string , arrowCount : number } {
2117
+ if ( valType === '::string' ) {
2118
+ valType = '' // No need to add a string conversion
2119
+ }
2120
+ const arrowCount = ( tkey . match ( / - > / g) ?? [ ] ) . length
2121
+ // We need to convert to type without array if pressent
2122
+ let tlkey = arrowCount > 0 ? `(${ tkey } )${ valType . replace ( '[]' , '' ) } ` : tkey
2123
+
2124
+ if ( arrowCount > 0 ) {
2125
+ // We need to replace only the last -> to ->>
2126
+ tlkey = arrowCount === 1 ? tlkey . replace ( '->' , '->>' ) : tlkey . replace ( / - > (? ! .* - > ) / , '->>' )
2127
+ }
2128
+ return { tlkey, arrowCount }
2129
+ }
2130
+
2096
2131
/**
2097
2132
* @public
2098
2133
*/
0 commit comments