Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export does not satisfy filename (Bun) #1731

Open
1 of 2 tasks
agucova opened this issue Sep 25, 2024 · 0 comments
Open
1 of 2 tasks

Export does not satisfy filename (Bun) #1731

agucova opened this issue Sep 25, 2024 · 0 comments

Comments

@agucova
Copy link

agucova commented Sep 25, 2024

Versions

  • sequelize: 6.37.3
  • sequelize-typescript: 2.1.6
  • typescript: 5.6.0

Issue type

  • bug report
  • feature request

The problem

While using Bun with sequelize-typescript, using paths for the models property fails to work when the relevant modules are ESM, throwing No default export defined for file "FILE" or export does not satisfy filename.

This is because Bun allows using require even if the target is an ES module:

In Bun's JavaScript runtime, require can be used by both ES Modules and CommonJS modules. If the target module is an ES Module, require returns the module namespace object (equivalent to import * as). If the target module is a CommonJS module, require returns the module.exports object (as in Node.js). Source

So what happens, is that the module is successfully imported through require , but when sequelize-typescript attempts to match over the attributes ( Object.keys(module)), it fails to find any.

const module = require(fullPath);
const fileName = basename(fullPath);
const matchedMemberKey = Object.keys(module).find((m) => modelMatch(fileName, m));
const matchedMember = matchedMemberKey ? module[matchedMemberKey] : undefined;
if (!matchedMember && !module.default) {
throw new Error(
`No default export defined for file "${fileName}" or ` +
`export does not satisfy filename.`
);
}

Per spec, exports of ES modules aren't enumerable attributes, so Object.keys(module) will return [] regardless of whether the attributes exist or not.

Steps to reproduce

index.ts

import { Sequelize } from "sequelize-typescript";

new Sequelize({
  database: "some_db",
  dialect: "sqlite",
  username: "root",
  password: "",
  storage: ":memory:",
  models: [__dirname + "/models"],
});

models/Person.ts:

import { Table, Column, Model } from 'sequelize-typescript';

@Table
export class Person extends Model {
  @Column
  name: string;

  @Column
  birthday: Date;
}
$ bun run index.ts
45 |                 const module = require(fullPath);
46 |                 const fileName = (0, path_1.basename)(fullPath);
47 |                 const matchedMemberKey = Object.keys(module).find((m) => modelMatch(fileName, m));
48 |                 const matchedMember = matchedMemberKey ? module[matchedMemberKey] : undefined;
49 |                 if (!matchedMember && !module.default) {
50 |                     throw new Error(`No default export defined for file "${fileName}" or ` +
                               ^
error: No default export defined for file "Person" or export does not satisfy filename.
      at node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize-service.js:50:27
      at map (1:11)
      at node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize-service.js:43:18
      at reduce (1:11)
      at addModels (node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize.js:36:48)
      at new Sequelize (node_modules/sequelize-typescript/dist/sequelize/sequelize/sequelize.js:20:22)
      at index.ts:4:1

Bun v1.1.27 (Linux x64)

What to do about it

Instead of using Object.keys, I believe we could just use for ... in, which would pick up the inherited enumerable attributes:

const module = require(fullPath);
const fileName = (0, path_1.basename)(fullPath);
const exports = []
for (const key in module) {
    exports.push(key);
}
const matchedMemberKey = exports.find((m) => modelMatch(fileName, m));

This works under Bun. That said, per #1660, I imagine this isn't a supported setup, so I mostly wanted to create this issue to prevent others from wasting several hours of their day trying to figure out what's wrong. If you're in this situation, you can get around this by importing the models directly and passing them to models:

import { Person } from "models/Person";
import { Sequelize } from "sequelize-typescript";

new Sequelize({
  database: "some_db",
  dialect: "sqlite",
  username: "root",
  password: "",
  storage: ":memory:",
  models: [Person],
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant