@@ -407,6 +407,79 @@ function buildAutoEmbedBlock(
407407 ) ;
408408}
409409
410+ /**
411+ * Build an auto-embed block for mutation handlers (create/update).
412+ *
413+ * Generates code equivalent to:
414+ * if (argv['auto-embed']) {
415+ * const embedder = resolveEmbedder();
416+ * if (!embedder) {
417+ * console.error('--auto-embed requires an embedder. Set EMBEDDER_PROVIDER=ollama');
418+ * process.exit(1);
419+ * }
420+ * await autoEmbedInput(cleanedData, ['embedding'], embedder);
421+ * }
422+ *
423+ * @param vectorFieldNames - Names of vector embedding fields detected at codegen time
424+ */
425+ function buildAutoEmbedInputBlock (
426+ vectorFieldNames : string [ ] ,
427+ ) : t . IfStatement {
428+ const fieldNamesArray = t . arrayExpression (
429+ vectorFieldNames . map ( ( n ) => t . stringLiteral ( n ) ) ,
430+ ) ;
431+
432+ const embedderDecl = t . variableDeclaration ( 'const' , [
433+ t . variableDeclarator (
434+ t . identifier ( 'embedder' ) ,
435+ t . callExpression ( t . identifier ( 'resolveEmbedder' ) , [ ] ) ,
436+ ) ,
437+ ] ) ;
438+
439+ const noEmbedderCheck = t . ifStatement (
440+ t . unaryExpression ( '!' , t . identifier ( 'embedder' ) ) ,
441+ t . blockStatement ( [
442+ t . expressionStatement (
443+ t . callExpression (
444+ t . memberExpression ( t . identifier ( 'console' ) , t . identifier ( 'error' ) ) ,
445+ [
446+ t . stringLiteral (
447+ '--auto-embed requires an embedder. Set EMBEDDER_PROVIDER=ollama (and optionally EMBEDDER_MODEL, EMBEDDER_BASE_URL).' ,
448+ ) ,
449+ ] ,
450+ ) ,
451+ ) ,
452+ t . expressionStatement (
453+ t . callExpression (
454+ t . memberExpression ( t . identifier ( 'process' ) , t . identifier ( 'exit' ) ) ,
455+ [ t . numericLiteral ( 1 ) ] ,
456+ ) ,
457+ ) ,
458+ ] ) ,
459+ ) ;
460+
461+ const autoEmbedCall = t . awaitExpression (
462+ t . callExpression ( t . identifier ( 'autoEmbedInput' ) , [
463+ t . identifier ( 'cleanedData' ) ,
464+ fieldNamesArray ,
465+ t . identifier ( 'embedder' ) ,
466+ ] ) ,
467+ ) ;
468+
469+ return t . ifStatement (
470+ t . memberExpression (
471+ t . identifier ( 'argv' ) ,
472+ t . stringLiteral ( 'auto-embed' ) ,
473+ true ,
474+ ) ,
475+ t . blockStatement ( [
476+ embedderDecl ,
477+ noEmbedderCheck ,
478+ t . expressionStatement ( autoEmbedCall ) ,
479+ ] ) ,
480+ ) ;
481+ }
482+
410483function buildListHandler ( table : Table , vectorFieldNames : string [ ] , targetName ?: string , typeRegistry ?: TypeRegistry ) : t . FunctionDeclaration {
411484 const { singularName } = getTableNames ( table ) ;
412485 const defaultSelectObj = buildSelectObject ( table , typeRegistry ) ;
@@ -904,6 +977,7 @@ export function getFieldsWithDefaults(
904977function buildMutationHandler (
905978 table : Table ,
906979 operation : 'create' | 'update' | 'delete' ,
980+ vectorFieldNames : string [ ] ,
907981 targetName ?: string ,
908982 typeRegistry ?: TypeRegistry ,
909983 ormTypes ?: { createInputTypeName : string ; innerFieldName : string ; patchTypeName : string } ,
@@ -1124,6 +1198,12 @@ function buildMutationHandler(
11241198 ) ,
11251199 ] ) ,
11261200 ) ;
1201+
1202+ // Inject --auto-embed block for create/update when table has vector fields.
1203+ // Converts text strings in vector fields to embeddings before the ORM call.
1204+ if ( vectorFieldNames . length > 0 ) {
1205+ tryBody . push ( buildAutoEmbedInputBlock ( vectorFieldNames ) ) ;
1206+ }
11271207 }
11281208
11291209 tryBody . push (
@@ -1257,7 +1337,7 @@ export function generateTableCommand(table: Table, options?: TableCommandOptions
12571337 if ( hasEmbeddings ) {
12581338 const embedderPath = options ?. targetName ? '../../embedder' : '../embedder' ;
12591339 statements . push (
1260- createImportDeclaration ( embedderPath , [ 'resolveEmbedder' , 'autoEmbedWhere' ] ) ,
1340+ createImportDeclaration ( embedderPath , [ 'resolveEmbedder' , 'autoEmbedWhere' , 'autoEmbedInput' ] ) ,
12611341 ) ;
12621342 }
12631343
@@ -1280,6 +1360,13 @@ export function generateTableCommand(table: Table, options?: TableCommandOptions
12801360 if ( hasGet ) usageLines . push ( ` get Get a ${ singularName } by ID` ) ;
12811361 usageLines . push ( ` create Create a new ${ singularName } ` ) ;
12821362 if ( hasUpdate ) usageLines . push ( ` update Update an existing ${ singularName } ` ) ;
1363+ if ( hasEmbeddings ) {
1364+ usageLines . push (
1365+ '' ,
1366+ 'Create/Update Options:' ,
1367+ ' --auto-embed Convert text values in vector fields to embeddings before saving' ,
1368+ ) ;
1369+ }
12831370 if ( hasDelete ) usageLines . push ( ` delete Delete a ${ singularName } ` ) ;
12841371 usageLines . push (
12851372 '' ,
@@ -1496,9 +1583,9 @@ export function generateTableCommand(table: Table, options?: TableCommandOptions
14961583 statements . push ( buildFindFirstHandler ( table , tn , options ?. typeRegistry ) ) ;
14971584 if ( hasSearchFields ) statements . push ( buildSearchHandler ( table , specialGroups , vectorFieldNames , tn , options ?. typeRegistry ) ) ;
14981585 if ( hasGet ) statements . push ( buildGetHandler ( table , tn , options ?. typeRegistry ) ) ;
1499- statements . push ( buildMutationHandler ( table , 'create' , tn , options ?. typeRegistry , ormTypes ) ) ;
1500- if ( hasUpdate ) statements . push ( buildMutationHandler ( table , 'update' , tn , options ?. typeRegistry , ormTypes ) ) ;
1501- if ( hasDelete ) statements . push ( buildMutationHandler ( table , 'delete' , tn , options ?. typeRegistry , ormTypes ) ) ;
1586+ statements . push ( buildMutationHandler ( table , 'create' , vectorFieldNames , tn , options ?. typeRegistry , ormTypes ) ) ;
1587+ if ( hasUpdate ) statements . push ( buildMutationHandler ( table , 'update' , vectorFieldNames , tn , options ?. typeRegistry , ormTypes ) ) ;
1588+ if ( hasDelete ) statements . push ( buildMutationHandler ( table , 'delete' , vectorFieldNames , tn , options ?. typeRegistry , ormTypes ) ) ;
15021589
15031590 const header = getGeneratedFileHeader ( `CLI commands for ${ table . name } ` ) ;
15041591 const code = generateCode ( statements ) ;
0 commit comments