diff --git a/core/actions/incremental_table_test.ts b/core/actions/incremental_table_test.ts index 8dfd9b032..35e317565 100644 --- a/core/actions/incremental_table_test.ts +++ b/core/actions/incremental_table_test.ts @@ -982,5 +982,161 @@ select \${incremental()} as is_incremental` expect(result.compile.compiledGraph.graphErrors.compilationErrors.length).greaterThan(0); expect(result.compile.compiledGraph.graphErrors.compilationErrors.some(e => e.message.includes("Cannot mix AoT and JiT compilation"))).equals(true); }); + + test("jit compilation is supported in sqlx", () => { + const projectDir = tmpDirFixture.createNewTmpDir(); + fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), VALID_WORKFLOW_SETTINGS_YAML); + fs.mkdirSync(path.join(projectDir, "definitions")); + fs.writeFileSync( + path.join(projectDir, "definitions/incremental.sqlx"), + `config { type: "incremental", compilation_mode: "jit" } +js { + const foo = "bar"; +} +SELECT 1 +\${when(incremental(), "WHERE 1=1")}` + ); + + const result = runMainInVm(coreExecutionRequestFromPath(projectDir)); + + expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]); + expect(asPlainObject(result.compile.compiledGraph.tables)).deep.equals([ + { + target: { + database: "defaultProject", + schema: "defaultDataset", + name: "incremental" + }, + canonicalTarget: { + database: "defaultProject", + schema: "defaultDataset", + name: "incremental" + }, + type: "incremental", + enumType: "INCREMENTAL", + disabled: false, + protected: false, + hermeticity: "NON_HERMETIC", + onSchemaChange: "IGNORE", + fileName: "definitions/incremental.sqlx", + jitCode: `async (jctx) => { + const self = jctx.self ? jctx.self.bind(jctx) : undefined; + const ref = jctx.ref ? jctx.ref.bind(jctx) : undefined; + const resolve = jctx.resolve ? jctx.resolve.bind(jctx) : undefined; + const name = jctx.name ? jctx.name.bind(jctx) : undefined; + const when = jctx.when ? jctx.when.bind(jctx) : undefined; + const incremental = jctx.incremental ? jctx.incremental.bind(jctx) : undefined; + const schema = jctx.schema ? jctx.schema.bind(jctx) : undefined; + const database = jctx.database ? jctx.database.bind(jctx) : undefined; + const adapter = jctx.adapter ? jctx.adapter : undefined; + const data = jctx.data ? jctx.data : undefined; + + const foo = "bar"; + + return { + query: ( + \` + +SELECT 1 +\${when(incremental(), "WHERE 1=1")}\` + ), + postOps: ( + undefined + ), + preOps: ( + undefined + ), + }; + }`, + actionDescriptor: { + compilationMode: "ACTION_COMPILATION_MODE_JIT" + } + } + ]); + }); + + test("jit compilation with pre/post ops is supported in sqlx", () => { + const projectDir = tmpDirFixture.createNewTmpDir(); + fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), VALID_WORKFLOW_SETTINGS_YAML); + fs.mkdirSync(path.join(projectDir, "definitions")); + fs.writeFileSync( + path.join(projectDir, "definitions/incremental.sqlx"), + `config { type: "incremental", compilation_mode: "jit" } +js { + const foo = "bar"; +} +SELECT 1 +\${when(incremental(), "WHERE 1=1")}; +pre_operations { + SELECT 10; +} +post_operations { + SELECT 20; +}` + ); + + const result = runMainInVm(coreExecutionRequestFromPath(projectDir)); + + expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]); + expect(asPlainObject(result.compile.compiledGraph.tables)).deep.equals([ + { + target: { + database: "defaultProject", + schema: "defaultDataset", + name: "incremental" + }, + canonicalTarget: { + database: "defaultProject", + schema: "defaultDataset", + name: "incremental" + }, + type: "incremental", + enumType: "INCREMENTAL", + disabled: false, + protected: false, + hermeticity: "NON_HERMETIC", + onSchemaChange: "IGNORE", + fileName: "definitions/incremental.sqlx", + jitCode: `async (jctx) => { + const self = jctx.self ? jctx.self.bind(jctx) : undefined; + const ref = jctx.ref ? jctx.ref.bind(jctx) : undefined; + const resolve = jctx.resolve ? jctx.resolve.bind(jctx) : undefined; + const name = jctx.name ? jctx.name.bind(jctx) : undefined; + const when = jctx.when ? jctx.when.bind(jctx) : undefined; + const incremental = jctx.incremental ? jctx.incremental.bind(jctx) : undefined; + const schema = jctx.schema ? jctx.schema.bind(jctx) : undefined; + const database = jctx.database ? jctx.database.bind(jctx) : undefined; + const adapter = jctx.adapter ? jctx.adapter : undefined; + const data = jctx.data ? jctx.data : undefined; + + const foo = "bar"; + + return { + query: ( + \` + +SELECT 1 +\${when(incremental(), "WHERE 1=1")}; + +\` + ), + postOps: ( + [\` + SELECT 20; +\`] + ), + preOps: ( + [\` + SELECT 10; +\`] + ), + }; + }`, + actionDescriptor: { + compilationMode: "ACTION_COMPILATION_MODE_JIT" + } + } + ]); + }); }); }); diff --git a/core/actions/operation_test.ts b/core/actions/operation_test.ts index d9541e171..a550d4cf3 100644 --- a/core/actions/operation_test.ts +++ b/core/actions/operation_test.ts @@ -255,5 +255,68 @@ actions: expect(result.compile.compiledGraph.graphErrors.compilationErrors.length).greaterThan(0); expect(result.compile.compiledGraph.graphErrors.compilationErrors.some(e => e.message.includes("Cannot mix AoT and JiT compilation"))).equals(true); }); + + test("jit compilation is supported in sqlx", () => { + const projectDir = tmpDirFixture.createNewTmpDir(); + fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), VALID_WORKFLOW_SETTINGS_YAML); + fs.mkdirSync(path.join(projectDir, "definitions")); + fs.writeFileSync( + path.join(projectDir, "definitions/op.sqlx"), + `config { type: "operations", compilation_mode: "jit" } +js { + const foo = "bar"; +} +SELECT 1 +--- +SELECT 2` + ); + + const result = runMainInVm(coreExecutionRequestFromPath(projectDir)); + + expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]); + expect(asPlainObject(result.compile.compiledGraph.operations)).deep.equals([ + { + target: { + database: "defaultProject", + schema: "defaultDataset", + name: "op" + }, + canonicalTarget: { + database: "defaultProject", + schema: "defaultDataset", + name: "op" + }, + hermeticity: "NON_HERMETIC", + fileName: "definitions/op.sqlx", + jitCode: `async (jctx) => { + const self = jctx.self ? jctx.self.bind(jctx) : undefined; + const ref = jctx.ref ? jctx.ref.bind(jctx) : undefined; + const resolve = jctx.resolve ? jctx.resolve.bind(jctx) : undefined; + const name = jctx.name ? jctx.name.bind(jctx) : undefined; + const when = jctx.when ? jctx.when.bind(jctx) : undefined; + const incremental = jctx.incremental ? jctx.incremental.bind(jctx) : undefined; + const schema = jctx.schema ? jctx.schema.bind(jctx) : undefined; + const database = jctx.database ? jctx.database.bind(jctx) : undefined; + const adapter = jctx.adapter ? jctx.adapter : undefined; + const data = jctx.data ? jctx.data : undefined; + + const foo = "bar"; + + return { + queries: [ + \` + +SELECT 1 +\`,\` +SELECT 2\` + ], + }; + }`, + actionDescriptor: { + compilationMode: "ACTION_COMPILATION_MODE_JIT" + } + } + ]); + }); }); }); diff --git a/core/actions/table_test.ts b/core/actions/table_test.ts index d9d0da684..c097a0b70 100644 --- a/core/actions/table_test.ts +++ b/core/actions/table_test.ts @@ -839,5 +839,153 @@ defaultIcebergConfig: expect(result.compile.compiledGraph.graphErrors.compilationErrors.length).greaterThan(0); expect(result.compile.compiledGraph.graphErrors.compilationErrors.some(e => e.message.includes("Cannot mix AoT and JiT compilation"))).equals(true); }); + + test("jit compilation is supported in sqlx", () => { + const projectDir = tmpDirFixture.createNewTmpDir(); + fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), VALID_WORKFLOW_SETTINGS_YAML); + fs.mkdirSync(path.join(projectDir, "definitions")); + fs.writeFileSync( + path.join(projectDir, "definitions/table.sqlx"), + `config { type: "table", compilation_mode: "jit" } +js { + const foo = "bar"; +} +SELECT 1` + ); + + const result = runMainInVm(coreExecutionRequestFromPath(projectDir)); + + expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]); + expect(asPlainObject(result.compile.compiledGraph.tables)).deep.equals([ + { + target: { + database: "defaultProject", + schema: "defaultDataset", + name: "table" + }, + canonicalTarget: { + database: "defaultProject", + schema: "defaultDataset", + name: "table" + }, + type: "table", + enumType: "TABLE", + disabled: false, + hermeticity: "NON_HERMETIC", + fileName: "definitions/table.sqlx", + jitCode: `async (jctx) => { + const self = jctx.self ? jctx.self.bind(jctx) : undefined; + const ref = jctx.ref ? jctx.ref.bind(jctx) : undefined; + const resolve = jctx.resolve ? jctx.resolve.bind(jctx) : undefined; + const name = jctx.name ? jctx.name.bind(jctx) : undefined; + const when = jctx.when ? jctx.when.bind(jctx) : undefined; + const incremental = jctx.incremental ? jctx.incremental.bind(jctx) : undefined; + const schema = jctx.schema ? jctx.schema.bind(jctx) : undefined; + const database = jctx.database ? jctx.database.bind(jctx) : undefined; + const adapter = jctx.adapter ? jctx.adapter : undefined; + const data = jctx.data ? jctx.data : undefined; + + const foo = "bar"; + + return { + query: ( + \` + +SELECT 1\` + ), + postOps: ( + undefined + ), + preOps: ( + undefined + ), + }; + }`, + actionDescriptor: { + compilationMode: "ACTION_COMPILATION_MODE_JIT" + } + } + ]); + }); + + test("jit compilation with pre/post ops is supported in sqlx", () => { + const projectDir = tmpDirFixture.createNewTmpDir(); + fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), VALID_WORKFLOW_SETTINGS_YAML); + fs.mkdirSync(path.join(projectDir, "definitions")); + fs.writeFileSync( + path.join(projectDir, "definitions/table.sqlx"), + `config { type: "table", compilation_mode: "jit" } +js { + const foo = "bar"; +} +SELECT 1 +pre_operations { + SELECT 10; +} +post_operations { + SELECT 20; +}` + ); + + const result = runMainInVm(coreExecutionRequestFromPath(projectDir)); + + expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]); + expect(asPlainObject(result.compile.compiledGraph.tables)).deep.equals([ + { + target: { + database: "defaultProject", + schema: "defaultDataset", + name: "table" + }, + canonicalTarget: { + database: "defaultProject", + schema: "defaultDataset", + name: "table" + }, + type: "table", + enumType: "TABLE", + disabled: false, + hermeticity: "NON_HERMETIC", + fileName: "definitions/table.sqlx", + jitCode: `async (jctx) => { + const self = jctx.self ? jctx.self.bind(jctx) : undefined; + const ref = jctx.ref ? jctx.ref.bind(jctx) : undefined; + const resolve = jctx.resolve ? jctx.resolve.bind(jctx) : undefined; + const name = jctx.name ? jctx.name.bind(jctx) : undefined; + const when = jctx.when ? jctx.when.bind(jctx) : undefined; + const incremental = jctx.incremental ? jctx.incremental.bind(jctx) : undefined; + const schema = jctx.schema ? jctx.schema.bind(jctx) : undefined; + const database = jctx.database ? jctx.database.bind(jctx) : undefined; + const adapter = jctx.adapter ? jctx.adapter : undefined; + const data = jctx.data ? jctx.data : undefined; + + const foo = "bar"; + + return { + query: ( + \` + +SELECT 1 + +\` + ), + postOps: ( + [\` + SELECT 20; +\`] + ), + preOps: ( + [\` + SELECT 10; +\`] + ), + }; + }`, + actionDescriptor: { + compilationMode: "ACTION_COMPILATION_MODE_JIT" + } + } + ]); + }); }); }); diff --git a/core/actions/view_test.ts b/core/actions/view_test.ts index d00baba6f..9d72706ee 100644 --- a/core/actions/view_test.ts +++ b/core/actions/view_test.ts @@ -378,5 +378,153 @@ ${exampleBuiltInAssertionsAsYaml.inputActionConfigBlock} expect(result.compile.compiledGraph.graphErrors.compilationErrors.length).greaterThan(0); expect(result.compile.compiledGraph.graphErrors.compilationErrors.some(e => e.message.includes("Cannot mix AoT and JiT compilation"))).equals(true); }); + + test("jit compilation is supported in sqlx", () => { + const projectDir = tmpDirFixture.createNewTmpDir(); + fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), VALID_WORKFLOW_SETTINGS_YAML); + fs.mkdirSync(path.join(projectDir, "definitions")); + fs.writeFileSync( + path.join(projectDir, "definitions/view.sqlx"), + `config { type: "view", compilation_mode: "jit" } +js { + const foo = "bar"; +} +SELECT 1` + ); + + const result = runMainInVm(coreExecutionRequestFromPath(projectDir)); + + expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]); + expect(asPlainObject(result.compile.compiledGraph.tables)).deep.equals([ + { + target: { + database: "defaultProject", + schema: "defaultDataset", + name: "view" + }, + canonicalTarget: { + database: "defaultProject", + schema: "defaultDataset", + name: "view" + }, + type: "view", + enumType: "VIEW", + disabled: false, + hermeticity: "NON_HERMETIC", + fileName: "definitions/view.sqlx", + jitCode: `async (jctx) => { + const self = jctx.self ? jctx.self.bind(jctx) : undefined; + const ref = jctx.ref ? jctx.ref.bind(jctx) : undefined; + const resolve = jctx.resolve ? jctx.resolve.bind(jctx) : undefined; + const name = jctx.name ? jctx.name.bind(jctx) : undefined; + const when = jctx.when ? jctx.when.bind(jctx) : undefined; + const incremental = jctx.incremental ? jctx.incremental.bind(jctx) : undefined; + const schema = jctx.schema ? jctx.schema.bind(jctx) : undefined; + const database = jctx.database ? jctx.database.bind(jctx) : undefined; + const adapter = jctx.adapter ? jctx.adapter : undefined; + const data = jctx.data ? jctx.data : undefined; + + const foo = "bar"; + + return { + query: ( + \` + +SELECT 1\` + ), + postOps: ( + undefined + ), + preOps: ( + undefined + ), + }; + }`, + actionDescriptor: { + compilationMode: "ACTION_COMPILATION_MODE_JIT" + } + } + ]); + }); + + test("jit compilation with pre/post ops is supported in sqlx", () => { + const projectDir = tmpDirFixture.createNewTmpDir(); + fs.writeFileSync(path.join(projectDir, "workflow_settings.yaml"), VALID_WORKFLOW_SETTINGS_YAML); + fs.mkdirSync(path.join(projectDir, "definitions")); + fs.writeFileSync( + path.join(projectDir, "definitions/view.sqlx"), + `config { type: "view", compilation_mode: "jit" } +js { + const foo = "bar"; +} +SELECT 1 +pre_operations { + SELECT 10; +} +post_operations { + SELECT 20; +}` + ); + + const result = runMainInVm(coreExecutionRequestFromPath(projectDir)); + + expect(result.compile.compiledGraph.graphErrors.compilationErrors).deep.equals([]); + expect(asPlainObject(result.compile.compiledGraph.tables)).deep.equals([ + { + target: { + database: "defaultProject", + schema: "defaultDataset", + name: "view" + }, + canonicalTarget: { + database: "defaultProject", + schema: "defaultDataset", + name: "view" + }, + type: "view", + enumType: "VIEW", + disabled: false, + hermeticity: "NON_HERMETIC", + fileName: "definitions/view.sqlx", + jitCode: `async (jctx) => { + const self = jctx.self ? jctx.self.bind(jctx) : undefined; + const ref = jctx.ref ? jctx.ref.bind(jctx) : undefined; + const resolve = jctx.resolve ? jctx.resolve.bind(jctx) : undefined; + const name = jctx.name ? jctx.name.bind(jctx) : undefined; + const when = jctx.when ? jctx.when.bind(jctx) : undefined; + const incremental = jctx.incremental ? jctx.incremental.bind(jctx) : undefined; + const schema = jctx.schema ? jctx.schema.bind(jctx) : undefined; + const database = jctx.database ? jctx.database.bind(jctx) : undefined; + const adapter = jctx.adapter ? jctx.adapter : undefined; + const data = jctx.data ? jctx.data : undefined; + + const foo = "bar"; + + return { + query: ( + \` + +SELECT 1 + +\` + ), + postOps: ( + [\` + SELECT 20; +\`] + ), + preOps: ( + [\` + SELECT 10; +\`] + ), + }; + }`, + actionDescriptor: { + compilationMode: "ACTION_COMPILATION_MODE_JIT" + } + } + ]); + }); }); }); diff --git a/core/compilers.ts b/core/compilers.ts index 69c8f7704..3bda8969f 100644 --- a/core/compilers.ts +++ b/core/compilers.ts @@ -22,6 +22,25 @@ const CONTEXT_CONSTANTS = [ .map(name => `const ${name} = ctx.${name} ? ctx.${name} : undefined;`) .join("\n"); +const JIT_CONTEXT_FUNCTIONS = [ + "self", + "ref", + "resolve", + "name", + "when", + "incremental", + "schema", + "database" +].map(name => `const ${name} = jctx.${name} ? jctx.${name}.bind(jctx) : undefined;`) + .join("\n "); + +const JIT_CONTEXT_CONSTANTS = [ + "adapter", + "data", +] + .map(name => `const ${name} = jctx.${name} ? jctx.${name} : undefined;`) + .join("\n "); + export const INVALID_YAML_ERROR_STRING = "is not a valid YAML file"; export function compile(code: string, path: string): string { @@ -83,9 +102,84 @@ export function extractJsBlocks(code: string): { sql: string; js: string } { } function compileSqlx(rootNode: SyntaxTreeNode, path: string): string { - const { config, js, sql, incremental, preOperations, postOperations, inputs } = extractSqlxParts( + const sqlxParts = extractSqlxParts( rootNode ); + const { config } = sqlxParts; + try { + // Part of the compilation, to be evalled in main compilation via require anyway. + // tslint:disable-next-line: tsr-detect-eval-with-expression + const sqlxConfig: { [key: string]: unknown } | undefined = new Function(`return ${config || "{}"}`)(); + if (!!sqlxConfig && sqlxConfig.hasOwnProperty("compilation_mode") && sqlxConfig.compilation_mode === "jit") { + const actionType = sqlxConfig.hasOwnProperty("type") ? sqlxConfig.type : "operations"; + if (typeof actionType !== "string") { + throw new Error(`Invalid action type: ${actionType} at ${path}.`); + } + return compileSqlxJit(sqlxParts, path, actionType); + } + } catch (_) { + // Let AoT compiler handle JS parsing errors + } + + return compileSqlxAot(sqlxParts, path); +} + +function makeSqlxJitReturnBlock(parts: SqlxParts, actionType: string): string { + const { sql, preOperations, postOperations } = parts; + switch (actionType) { + case "operations": + return `return { + queries: [ + ${sql.map(sqlOp => `\`${sqlOp}\``)} + ], + };`; + case "incremental": + case "table": + case "view": + if (sql.length > 1) { + throw new Error("Table and views must have at most 1 SQL statement."); + } + return `return { + query: ( + \`${sql[0]}\` + ), + postOps: ( + ${postOperations.length > 0 ? ('[' + postOperations.map(postOpSql => `\`${postOpSql}\``) + ']') : 'undefined'} + ), + preOps: ( + ${preOperations.length > 0 ? ('[' + preOperations.map(preOpSql => `\`${preOpSql}\``) + ']') : 'undefined'} + ), + };`; + default: + throw new Error(`Invalid action type: ${actionType}`); + } +} + +function compileSqlxJit(parts: SqlxParts, path: string, actionType: string): string { + const { config, js } = parts; + const returnBlock = makeSqlxJitReturnBlock(parts, actionType); + + return `dataform.sqlxJitAction({ + sqlxConfig: { + name: "${Path.escapedBasename(path)}", + type: "operations", + ...${config || "{}"} + }, + jitCode: "` + `async (jctx) => { + ${JIT_CONTEXT_FUNCTIONS} + ${JIT_CONTEXT_CONSTANTS} + ${js} + ${returnBlock} + }` + .replace(/\\/, "\\\\") + .replace(/\r?\n/g, "\\n") + .replace(/\"/g, "\\\"") + `" + }); + `; +} + +function compileSqlxAot(parts: SqlxParts, path: string): string { + const { config, js, sql, incremental, preOperations, postOperations, inputs } = parts; return `dataform.sqlxAction({ sqlxConfig: { @@ -148,6 +242,8 @@ function compileSqlx(rootNode: SyntaxTreeNode, path: string): string { `; } +type SqlxParts = ReturnType; + function extractSqlxParts(rootNode: SyntaxTreeNode) { let config = ""; let js = ""; diff --git a/core/session.ts b/core/session.ts index 6f3fe0574..2b0821dec 100644 --- a/core/session.ts +++ b/core/session.ts @@ -113,17 +113,14 @@ export class Session { ]; }) { const { sqlxConfig } = actionOptions; - const actionType = sqlxConfig.hasOwnProperty("type") ? sqlxConfig.type : "operations"; + const actionType = this.processSqlxConfig(actionOptions); + if (actionOptions.sqlStatementCount > 1 && actionType !== "operations") { this.compileError( "Actions may only contain more than one SQL statement if they are of type 'operations'." ); } - if (sqlxConfig.hasOwnProperty("protected") && actionType !== "incremental") { - this.compileError( - "Actions may only specify 'protected: true' if they are of type 'incremental'." - ); - } + if (actionOptions.incrementalWhereContextable && actionType !== "incremental") { this.compileError( "Actions may only include incremental_where if they are of type 'incremental'." @@ -218,6 +215,44 @@ export class Session { } } + public sqlxJitAction(actionOptions: { + sqlxConfig: any, + jitCode: string, + }) { + const { sqlxConfig, jitCode } = actionOptions; + const actionType = this.processSqlxConfig(actionOptions); + + if (!sqlxConfig.filename) { + sqlxConfig.filename = utils.getCallerFile(this.rootDir); + } + const jitConfig = {...sqlxConfig}; + delete jitConfig.compilation_mode; + + switch (actionType) { + case "view": + const view = new View(this, jitConfig).jitCode(jitCode); + this.actions.push(view); + break; + case "incremental": + const incrementalTable = new IncrementalTable(this, jitConfig).jitCode(jitCode); + this.actions.push(incrementalTable); + break; + case "table": + const table = new Table(this, jitConfig).jitCode(jitCode); + this.actions.push(table); + break; + case "operations": + this.actions.push(new Operation(this, jitConfig).jitCode(jitCode)); + break; + case "declaration": + const declaration = new Declaration(this, jitConfig, jitConfig.filename); + this.actions.push(declaration); + break; + default: + throw new Error(`Unsupported by JiT compilation mode action type: ${jitConfig.type}`); + } + } + public resolve(ref: Resolvable | string[], ...rest: string[]): string { ref = toResolvable(ref, rest); const allResolved = this.indexedActions.find(utils.resolvableAsTarget(ref)); @@ -645,6 +680,21 @@ export class Session { }); } + private processSqlxConfig(actionOptions: { + sqlxConfig: any; + }): string { + const { sqlxConfig } = actionOptions; + + const actionType = sqlxConfig.hasOwnProperty("type") ? sqlxConfig.type : "operations"; + if (sqlxConfig.hasOwnProperty("protected") && actionType !== "incremental") { + this.compileError( + "Actions may only specify 'protected: true' if they are of type 'incremental'." + ); + } + + return actionType; + } + private alterActionName(actions: ActionProto[], declarationTargets: dataform.ITarget[]) { const { tablePrefix, schemaSuffix, databaseSuffix } = this.projectConfig;