Repository: FlowiseAI/Flowise
File: packages/server/src/database/migrations/sqlite/1759419136055-AddTextToSpeechToChatFlow.ts (TypeScript)

Code before:
import { MigrationInterface, QueryRunner } from 'typeorm'

export class AddTextToSpeechToChatFlow1759419136055 implements MigrationInterface {
    public async up(queryRunner: QueryRunner): Promise<void> {
        const tableInfo = await queryRunner.query(`PRAGMA table_info("chat_flow");`)
        const columnExists = tableInfo.some((column: any) => column.name === 'textToSpeech')
        if (!columnExists) {
            await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "textToSpeech" TEXT;`)
        }
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "chat_flow" DROP COLUMN "textToSpeech";`)
    }
}


Review comment (suggestion):
This migration **will partially work** with SQLite and TypeORM, but there are some caveats:

### The `up` Method

- **Adding a column:**  
  ```typescript
  await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "textToSpeech" TEXT;`)
  ```
  This works in SQLite. Adding a new column to an existing table is supported.

### The `down` Method

- **Dropping a column:**  
  ```typescript
  await queryRunner.query(`ALTER TABLE "chat_flow" DROP COLUMN "textToSpeech";`)
  ```
  **This will NOT work in SQLite!**  
  SQLite **does not support** the `DROP COLUMN` syntax directly (as of SQLite 3.35.0, released March 2021, it started supporting it, but many environments still use older versions, and TypeORM itself may not handle this well).

  The usual workaround is:
  1. Create a new table without the column.
  2. Copy the data over.
  3. Drop the old table.
  4. Rename the new table.

  TypeORM migrations for SQLite typically implement this workaround in the `down` method.

---

## **Summary**

- `up`: **Works** (adds the column).
- `down`: **May NOT work** (dropping columns in SQLite is unreliable).

---

## **What should you do?**

If you want your migration to work reliably in SQLite, update the `down` method to use the [recommended workaround](https://www.sqlite.org/lang_altertable.html#otheralter) for dropping a column.

**Example workaround for the `down` method:**
```typescript
public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
        CREATE TABLE "chat_flow_temp" AS SELECT * FROM "chat_flow" WHERE 1=0;
    `);
    await queryRunner.query(`
        INSERT INTO "chat_flow_temp" SELECT id, ... FROM "chat_flow";
    `);
    await queryRunner.query(`DROP TABLE "chat_flow";`);
    await queryRunner.query(`ALTER TABLE "chat_flow_temp" RENAME TO "chat_flow";`);
}
```
*(You must list all columns except `textToSpeech` in the SELECT and INSERT statements.)*

Code after:
import { MigrationInterface, QueryRunner } from 'typeorm'

export class AddTextToSpeechToChatFlow1759419136055 implements MigrationInterface {
    public async up(queryRunner: QueryRunner): Promise<void> {
        const tableInfo = await queryRunner.query(`PRAGMA table_info("chat_flow");`)
        const columnExists = tableInfo.some((column: any) => column.name === 'textToSpeech')
        if (!columnExists) {
            await queryRunner.query(`ALTER TABLE "chat_flow" ADD COLUMN "textToSpeech" TEXT;`)
        }
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`CREATE TABLE "chat_flow_temp" AS SELECT * FROM "chat_flow" WHERE 1=0;`)
        await queryRunner.query(`
            INSERT INTO "chat_flow_temp"
            SELECT id, name, flowData, deployed, isPublic, apikeyid, chatbotConfig, apiConfig, analytic, speechToText, followUpPrompts, category, type, createdDate, updatedDate, workspaceId
            FROM "chat_flow";
        `)
        await queryRunner.query(`DROP TABLE "chat_flow";`)
        await queryRunner.query(`ALTER TABLE "chat_flow_temp" RENAME TO "chat_flow";`)
    }
}