@@ -1322,6 +1322,275 @@ function buildMutationHandler(
13221322 ) ;
13231323}
13241324
1325+ type BulkCliOp = 'bulk-create' | 'bulk-upsert' | 'bulk-update' | 'bulk-delete' ;
1326+
1327+ function buildBulkMutationHandler (
1328+ table : Table ,
1329+ operation : BulkCliOp ,
1330+ targetName ?: string ,
1331+ ) : t . FunctionDeclaration {
1332+ const { singularName } = getTableNames ( table ) ;
1333+ const selectObj = buildSelectObject ( table ) ;
1334+
1335+ // Map CLI op name to ORM method name
1336+ const ormMethod = ( ( ) => {
1337+ switch ( operation ) {
1338+ case 'bulk-create' : return 'bulkCreate' ;
1339+ case 'bulk-upsert' : return 'bulkUpsert' ;
1340+ case 'bulk-update' : return 'bulkUpdate' ;
1341+ case 'bulk-delete' : return 'bulkDelete' ;
1342+ }
1343+ } ) ( ) ;
1344+
1345+ const tryBody : t . Statement [ ] = [ ] ;
1346+
1347+ if ( operation === 'bulk-create' || operation === 'bulk-upsert' ) {
1348+ // Parse --data (JSON array) from argv
1349+ tryBody . push (
1350+ t . variableDeclaration ( 'const' , [
1351+ t . variableDeclarator (
1352+ t . identifier ( 'dataRaw' ) ,
1353+ t . memberExpression ( t . identifier ( 'argv' ) , t . identifier ( 'data' ) ) ,
1354+ ) ,
1355+ ] ) ,
1356+ ) ;
1357+ tryBody . push (
1358+ t . ifStatement (
1359+ t . unaryExpression ( '!' , t . identifier ( 'dataRaw' ) ) ,
1360+ t . blockStatement ( [
1361+ t . expressionStatement (
1362+ t . callExpression (
1363+ t . memberExpression ( t . identifier ( 'console' ) , t . identifier ( 'error' ) ) ,
1364+ [ t . stringLiteral ( `--data is required for ${ operation } . Provide a JSON array.` ) ] ,
1365+ ) ,
1366+ ) ,
1367+ t . expressionStatement (
1368+ t . callExpression (
1369+ t . memberExpression ( t . identifier ( 'process' ) , t . identifier ( 'exit' ) ) ,
1370+ [ t . numericLiteral ( 1 ) ] ,
1371+ ) ,
1372+ ) ,
1373+ ] ) ,
1374+ ) ,
1375+ ) ;
1376+ tryBody . push (
1377+ t . variableDeclaration ( 'const' , [
1378+ t . variableDeclarator (
1379+ t . identifier ( 'data' ) ,
1380+ t . callExpression (
1381+ t . memberExpression ( t . identifier ( 'JSON' ) , t . identifier ( 'parse' ) ) ,
1382+ [ t . tsAsExpression ( t . identifier ( 'dataRaw' ) , t . tsStringKeyword ( ) ) ] ,
1383+ ) ,
1384+ ) ,
1385+ ] ) ,
1386+ ) ;
1387+
1388+ let ormArgs : t . ObjectExpression ;
1389+ if ( operation === 'bulk-upsert' ) {
1390+ // Also parse --on-conflict
1391+ tryBody . push (
1392+ t . variableDeclaration ( 'const' , [
1393+ t . variableDeclarator (
1394+ t . identifier ( 'onConflictRaw' ) ,
1395+ t . memberExpression ( t . identifier ( 'argv' ) , t . identifier ( 'on-conflict' ) ) ,
1396+ ) ,
1397+ ] ) ,
1398+ ) ;
1399+ tryBody . push (
1400+ t . variableDeclaration ( 'const' , [
1401+ t . variableDeclarator (
1402+ t . identifier ( 'onConflict' ) ,
1403+ t . conditionalExpression (
1404+ t . identifier ( 'onConflictRaw' ) ,
1405+ t . callExpression (
1406+ t . memberExpression ( t . identifier ( 'JSON' ) , t . identifier ( 'parse' ) ) ,
1407+ [ t . tsAsExpression ( t . identifier ( 'onConflictRaw' ) , t . tsStringKeyword ( ) ) ] ,
1408+ ) ,
1409+ t . objectExpression ( [ ] ) ,
1410+ ) ,
1411+ ) ,
1412+ ] ) ,
1413+ ) ;
1414+ ormArgs = t . objectExpression ( [
1415+ t . objectProperty ( t . identifier ( 'data' ) , t . identifier ( 'data' ) ) ,
1416+ t . objectProperty ( t . identifier ( 'onConflict' ) , t . identifier ( 'onConflict' ) ) ,
1417+ t . objectProperty ( t . identifier ( 'select' ) , selectObj ) ,
1418+ ] ) ;
1419+ } else {
1420+ ormArgs = t . objectExpression ( [
1421+ t . objectProperty ( t . identifier ( 'data' ) , t . identifier ( 'data' ) ) ,
1422+ t . objectProperty ( t . identifier ( 'select' ) , selectObj ) ,
1423+ ] ) ;
1424+ }
1425+
1426+ tryBody . push ( buildGetClientStatement ( targetName ) ) ;
1427+ tryBody . push (
1428+ t . variableDeclaration ( 'const' , [
1429+ t . variableDeclarator (
1430+ t . identifier ( 'result' ) ,
1431+ t . awaitExpression ( buildOrmCall ( singularName , ormMethod , ormArgs ) ) ,
1432+ ) ,
1433+ ] ) ,
1434+ ) ;
1435+ } else if ( operation === 'bulk-update' ) {
1436+ // Parse --where (JSON) and --data (JSON)
1437+ tryBody . push (
1438+ t . variableDeclaration ( 'const' , [
1439+ t . variableDeclarator (
1440+ t . identifier ( 'whereRaw' ) ,
1441+ t . memberExpression ( t . identifier ( 'argv' ) , t . identifier ( 'where' ) ) ,
1442+ ) ,
1443+ ] ) ,
1444+ ) ;
1445+ tryBody . push (
1446+ t . variableDeclaration ( 'const' , [
1447+ t . variableDeclarator (
1448+ t . identifier ( 'dataRaw' ) ,
1449+ t . memberExpression ( t . identifier ( 'argv' ) , t . identifier ( 'data' ) ) ,
1450+ ) ,
1451+ ] ) ,
1452+ ) ;
1453+ tryBody . push (
1454+ t . ifStatement (
1455+ t . logicalExpression (
1456+ '||' ,
1457+ t . unaryExpression ( '!' , t . identifier ( 'whereRaw' ) ) ,
1458+ t . unaryExpression ( '!' , t . identifier ( 'dataRaw' ) ) ,
1459+ ) ,
1460+ t . blockStatement ( [
1461+ t . expressionStatement (
1462+ t . callExpression (
1463+ t . memberExpression ( t . identifier ( 'console' ) , t . identifier ( 'error' ) ) ,
1464+ [ t . stringLiteral ( '--where and --data are required for bulk-update. Provide JSON objects.' ) ] ,
1465+ ) ,
1466+ ) ,
1467+ t . expressionStatement (
1468+ t . callExpression (
1469+ t . memberExpression ( t . identifier ( 'process' ) , t . identifier ( 'exit' ) ) ,
1470+ [ t . numericLiteral ( 1 ) ] ,
1471+ ) ,
1472+ ) ,
1473+ ] ) ,
1474+ ) ,
1475+ ) ;
1476+ tryBody . push (
1477+ t . variableDeclaration ( 'const' , [
1478+ t . variableDeclarator (
1479+ t . identifier ( 'where' ) ,
1480+ t . callExpression (
1481+ t . memberExpression ( t . identifier ( 'JSON' ) , t . identifier ( 'parse' ) ) ,
1482+ [ t . tsAsExpression ( t . identifier ( 'whereRaw' ) , t . tsStringKeyword ( ) ) ] ,
1483+ ) ,
1484+ ) ,
1485+ ] ) ,
1486+ ) ;
1487+ tryBody . push (
1488+ t . variableDeclaration ( 'const' , [
1489+ t . variableDeclarator (
1490+ t . identifier ( 'data' ) ,
1491+ t . callExpression (
1492+ t . memberExpression ( t . identifier ( 'JSON' ) , t . identifier ( 'parse' ) ) ,
1493+ [ t . tsAsExpression ( t . identifier ( 'dataRaw' ) , t . tsStringKeyword ( ) ) ] ,
1494+ ) ,
1495+ ) ,
1496+ ] ) ,
1497+ ) ;
1498+ tryBody . push ( buildGetClientStatement ( targetName ) ) ;
1499+ tryBody . push (
1500+ t . variableDeclaration ( 'const' , [
1501+ t . variableDeclarator (
1502+ t . identifier ( 'result' ) ,
1503+ t . awaitExpression (
1504+ buildOrmCall ( singularName , ormMethod , t . objectExpression ( [
1505+ t . objectProperty ( t . identifier ( 'where' ) , t . identifier ( 'where' ) ) ,
1506+ t . objectProperty ( t . identifier ( 'data' ) , t . identifier ( 'data' ) ) ,
1507+ t . objectProperty ( t . identifier ( 'select' ) , selectObj ) ,
1508+ ] ) ) ,
1509+ ) ,
1510+ ) ,
1511+ ] ) ,
1512+ ) ;
1513+ } else {
1514+ // bulk-delete: parse --where (JSON)
1515+ tryBody . push (
1516+ t . variableDeclaration ( 'const' , [
1517+ t . variableDeclarator (
1518+ t . identifier ( 'whereRaw' ) ,
1519+ t . memberExpression ( t . identifier ( 'argv' ) , t . identifier ( 'where' ) ) ,
1520+ ) ,
1521+ ] ) ,
1522+ ) ;
1523+ tryBody . push (
1524+ t . ifStatement (
1525+ t . unaryExpression ( '!' , t . identifier ( 'whereRaw' ) ) ,
1526+ t . blockStatement ( [
1527+ t . expressionStatement (
1528+ t . callExpression (
1529+ t . memberExpression ( t . identifier ( 'console' ) , t . identifier ( 'error' ) ) ,
1530+ [ t . stringLiteral ( '--where is required for bulk-delete. Provide a JSON object.' ) ] ,
1531+ ) ,
1532+ ) ,
1533+ t . expressionStatement (
1534+ t . callExpression (
1535+ t . memberExpression ( t . identifier ( 'process' ) , t . identifier ( 'exit' ) ) ,
1536+ [ t . numericLiteral ( 1 ) ] ,
1537+ ) ,
1538+ ) ,
1539+ ] ) ,
1540+ ) ,
1541+ ) ;
1542+ tryBody . push (
1543+ t . variableDeclaration ( 'const' , [
1544+ t . variableDeclarator (
1545+ t . identifier ( 'where' ) ,
1546+ t . callExpression (
1547+ t . memberExpression ( t . identifier ( 'JSON' ) , t . identifier ( 'parse' ) ) ,
1548+ [ t . tsAsExpression ( t . identifier ( 'whereRaw' ) , t . tsStringKeyword ( ) ) ] ,
1549+ ) ,
1550+ ) ,
1551+ ] ) ,
1552+ ) ;
1553+ tryBody . push ( buildGetClientStatement ( targetName ) ) ;
1554+ tryBody . push (
1555+ t . variableDeclaration ( 'const' , [
1556+ t . variableDeclarator (
1557+ t . identifier ( 'result' ) ,
1558+ t . awaitExpression (
1559+ buildOrmCall ( singularName , ormMethod , t . objectExpression ( [
1560+ t . objectProperty ( t . identifier ( 'where' ) , t . identifier ( 'where' ) ) ,
1561+ t . objectProperty ( t . identifier ( 'select' ) , selectObj ) ,
1562+ ] ) ) ,
1563+ ) ,
1564+ ) ,
1565+ ] ) ,
1566+ ) ;
1567+ }
1568+
1569+ tryBody . push ( buildJsonLog ( t . identifier ( 'result' ) ) ) ;
1570+
1571+ const argvParam = t . identifier ( 'argv' ) ;
1572+ argvParam . typeAnnotation = buildArgvType ( ) ;
1573+ const prompterParam = t . identifier ( 'prompter' ) ;
1574+ prompterParam . typeAnnotation = t . tsTypeAnnotation (
1575+ t . tsTypeReference ( t . identifier ( 'Inquirerer' ) ) ,
1576+ ) ;
1577+
1578+ const handlerName = `handle${ toPascalCase ( operation ) } ` ;
1579+
1580+ return t . functionDeclaration (
1581+ t . identifier ( handlerName ) ,
1582+ [ argvParam , prompterParam ] ,
1583+ t . blockStatement ( [
1584+ t . tryStatement (
1585+ t . blockStatement ( tryBody ) ,
1586+ buildErrorCatch ( `Failed to ${ operation } .` ) ,
1587+ ) ,
1588+ ] ) ,
1589+ false ,
1590+ true ,
1591+ ) ;
1592+ }
1593+
13251594export interface TableCommandOptions {
13261595 targetName ?: string ;
13271596 executorImportPath ?: string ;
@@ -1439,12 +1708,22 @@ export function generateTableCommand(table: Table, options?: TableCommandOptions
14391708 ) ;
14401709 }
14411710
1711+ // Detect bulk mutations
1712+ const hasBulkCreate = ! ! table . query ?. bulkInsert ;
1713+ const hasBulkUpsert = ! ! table . query ?. bulkUpsert ;
1714+ const hasBulkUpdate = ! ! table . query ?. bulkUpdate ;
1715+ const hasBulkDelete = ! ! table . query ?. bulkDelete ;
1716+
14421717 const subcommands : string [ ] = [ 'list' , 'find-first' ] ;
14431718 if ( hasSearchFields ) subcommands . push ( 'search' ) ;
14441719 if ( hasGet ) subcommands . push ( 'get' ) ;
14451720 subcommands . push ( 'create' ) ;
14461721 if ( hasUpdate ) subcommands . push ( 'update' ) ;
14471722 if ( hasDelete ) subcommands . push ( 'delete' ) ;
1723+ if ( hasBulkCreate ) subcommands . push ( 'bulk-create' ) ;
1724+ if ( hasBulkUpsert ) subcommands . push ( 'bulk-upsert' ) ;
1725+ if ( hasBulkUpdate ) subcommands . push ( 'bulk-update' ) ;
1726+ if ( hasBulkDelete ) subcommands . push ( 'bulk-delete' ) ;
14481727
14491728 const usageLines = [
14501729 '' ,
@@ -1466,6 +1745,10 @@ export function generateTableCommand(table: Table, options?: TableCommandOptions
14661745 ) ;
14671746 }
14681747 if ( hasDelete ) usageLines . push ( ` delete Delete a ${ singularName } ` ) ;
1748+ if ( hasBulkCreate ) usageLines . push ( ` bulk-create Bulk create ${ singularName } records` ) ;
1749+ if ( hasBulkUpsert ) usageLines . push ( ` bulk-upsert Bulk upsert ${ singularName } records` ) ;
1750+ if ( hasBulkUpdate ) usageLines . push ( ` bulk-update Bulk update ${ singularName } records` ) ;
1751+ if ( hasBulkDelete ) usageLines . push ( ` bulk-delete Bulk delete ${ singularName } records` ) ;
14691752 usageLines . push (
14701753 '' ,
14711754 'List Options:' ,
@@ -1684,6 +1967,10 @@ export function generateTableCommand(table: Table, options?: TableCommandOptions
16841967 statements . push ( buildMutationHandler ( table , 'create' , vectorFieldNames , tn , options ?. typeRegistry , ormTypes ) ) ;
16851968 if ( hasUpdate ) statements . push ( buildMutationHandler ( table , 'update' , vectorFieldNames , tn , options ?. typeRegistry , ormTypes ) ) ;
16861969 if ( hasDelete ) statements . push ( buildMutationHandler ( table , 'delete' , vectorFieldNames , tn , options ?. typeRegistry , ormTypes ) ) ;
1970+ if ( hasBulkCreate ) statements . push ( buildBulkMutationHandler ( table , 'bulk-create' , tn ) ) ;
1971+ if ( hasBulkUpsert ) statements . push ( buildBulkMutationHandler ( table , 'bulk-upsert' , tn ) ) ;
1972+ if ( hasBulkUpdate ) statements . push ( buildBulkMutationHandler ( table , 'bulk-update' , tn ) ) ;
1973+ if ( hasBulkDelete ) statements . push ( buildBulkMutationHandler ( table , 'bulk-delete' , tn ) ) ;
16871974
16881975 const header = getGeneratedFileHeader ( `CLI commands for ${ table . name } ` ) ;
16891976 const code = generateCode ( statements ) ;
0 commit comments