Skip to content

knex.migrate.latest() fails when ...knexSnakeCaseMappers is part of the knex config #2192

@cauboy

Description

@cauboy

I'm having the following issue:

When trying to do migration with an "knexSnakeCaseMappers"-ized knex instance using "objection": "3.0.1" and knex": "^0.95.15", the migration fails with the following error:

migration file "1.ts" failed
migration failed with error: Cannot read properties of undefined (reading 'lastIndexOf')

 TypeError {
    message: 'Cannot read properties of undefined (reading \'lastIndexOf\')',
  }

  › node_modules/objection/lib/utils/identifierMapping.js:139:21
  › node_modules/objection/lib/utils/identifierMapping.js:13:16
  › Object.wrapIdentifier (node_modules/objection/lib/utils/identifierMapping.js:180:23)
  › Client_SQLite3.customWrapIdentifier (node_modules/knex/lib/client.js:177:26)
  › TableCompiler_SQLite3.primary (node_modules/knex/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js:192:34)
  › TableCompiler_SQLite3.alterTable (node_modules/knex/lib/schema/tablecompiler.js:245:32)
  › TableCompiler_SQLite3.create (node_modules/knex/lib/schema/tablecompiler.js:59:10)
  › TableCompiler_SQLite3.toSQL (node_modules/knex/lib/schema/tablecompiler.js:39:22)
  › TableBuilder.toSQL (node_modules/knex/lib/schema/tablebuilder.js:49:44)
  › SchemaCompiler_SQLite3.build (node_modules/knex/lib/schema/compiler.js:143:23)

How to reproduce:

The error is thrown when running ts-node migrate.ts

// migrate.ts
import { db } from '../src/db
db.migrate.latest() // <--- This command fails
// db.ts
import { knexSnakeCaseMappers } from 'objection'
export const db = knex({
  client: 'sqlite3',
  migrations: { tableName: 'knex_migrations', },
  connection: { filename: './sqlite.db' },
  useNullAsDefault: true,
  ...knexSnakeCaseMappers(),
})
// migrations/1.ts
import { Knex } from 'knex'
export function up(knex: Knex) {
  return knex.schema.createTable('example', (table) => {
    table.uuid('id').primary()
  })
}

export function down(knex: Knex) {
  return knex.schema.dropTable('example')
}

Possible solution

The issue is that undefined is passed as the value for the str parameter to the function that is returned from mapLastPart. I could fix the issue by returning the identity whenever str is not a String

// node_modules/objection/lib/utils/identifierMapping.js
function mapLastPart(mapper, separator) {
  return (str) => {
    // if (typeof str !== 'string' ) { return str } // <--- Potential fix
    const idx = str.lastIndexOf(separator);
    const mapped = mapper(str.slice(idx + separator.length));
    return str.slice(0, idx + separator.length) + mapped;
  };
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions