question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Uncaught ReferenceError: Cannot access Model before initializaion on a One-to-Many relatioship.

See original GitHub issue

Hello, im trying to make a simple One-to-Many relationship between 2 models, users and surveys, using postgres 12.3 and denodb 1.0.4.

Following the documentation i’ve created ahasMany and a hasOne function on each corresponding model, and added a new field using the Relationships.belongsTo(User) to the Survey model.

Everything works fine until i add the new field Relationships.belongsTo(User) getting the following error.

error: Uncaught ReferenceError: Cannot access 'User' before initialization
    userId: Relationships.belongsTo(User),
                                    ^
    at Survey.ts:23:37
    at Survey.ts:35:2
    at <anonymous> (<anonymous>)

Here’s how my code looks:

The User model:

// Users.ts: The user model.
import { DataTypes, Model } from "../depts.ts";
import Survey from "./Survey.ts";

export default class User extends Model {
  static table = "users";
  static timestamps = true;

  static fields = {
    id: { primaryKey: true, autoIncrement: true },
    name: DataTypes.STRING,
    email: {
      type: DataTypes.STRING,
      unique: true,
      allowNull: false,
      length: 50,
    },
    password: DataTypes.STRING,
  };

  // Fetch surveys binded to this user
  static surveys() {
    return this.hasMany(Survey);
  }

  // Model record
  id!: number;
  name!: string;
  email!: string;
  password!: string;
}

The Survey model:

// Survey.ts: The survey model.
import { DataTypes, Model, Relationships } from "../depts.ts";
import User from "./User.ts";

export default class Survey extends Model {
  static table = "surveys";
  static timestamps = true;

  static fields = {
    id: { primaryKey: true, autoIncrement: true },
    name: {
      type: DataTypes.STRING,
      unique: false,
      allowNull: false,
      length: 50,
    },
    description: {
      type: DataTypes.STRING,
      unique: false,
      allowNull: false,
      length: 200,
    },
    userId: Relationships.belongsTo(User),
  };

  // Fetch an user binded to this survey
  static user() {
    return this.hasOne(User);
  }

  // Model record
  id!: number;
  name!: string;
  description!: string;
}

The database connector:

// dbconnector.ts: the database connector
import { Database } from "./depts.ts";
import User from "./Models/User.ts";
import Survey from "./Models/Survey.ts";

// Database credentials are specified on a .env file on the same level as server.ts
const db: Database = new Database("postgres", {
  host: `${Deno.env.get("DB_HOST")}`,
  username: `${Deno.env.get("DB_USERNAME")}`,
  password: `${Deno.env.get("DB_PASSWORD")}`,
  database: `${Deno.env.get("DB_NAME")}`,
});

// Models to link:
db.link([User, Survey]);

export default db;

And the server file:

// server.ts: server gateway and app initializers.
import {
  Application,
} from "./depts.ts";
import db from "./dbconnector.ts";
import router from "./router.ts";

await db.sync({ drop: true });
if (db.getConnector()._connected) {
  console.log("Database connected successfully!");
  // console.log(db.getConnector());
}

const app = new Application();

app.use(router.routes());
app.use(router.allowedMethods());

app.addEventListener("listen", ({ hostname, port, secure }) => {
  console.log(
    `Listening on ${secure ? "https" : "http"}://${hostname ||
      "localhost"}:${port}`,
  );
});

await app.listen({ port: 8000 });
await db.close();

And my depts file:

// depts.ts: master dependencies file, the depths of hell.
import "https://deno.land/x/dotenv@v0.5.0/load.ts";

export {
  Application,
  Router,
  RouterContext,
} from "https://deno.land/x/oak@v5.3.1/mod.ts";

export {
  DATA_TYPES,
  DataTypes,
  Database,
  Model,
  Relationships,
} from "https://deno.land/x/denodb@v1.0.4/mod.ts";

export {
  compareSync,
  hashSync,
} from "https://deno.land/x/bcrypt@v0.2.2/mod.ts";

export {
  makeJwt,
  setExpiration,
  Jose,
  Payload,
} from "https://deno.land/x/djwt@v0.9.0/create.ts";

export { validateJwt } from "https://deno.land/x/djwt@v0.9.0/validate.ts";

Full code can be reviewed here: https://github.com/Frenzoid/oak-deno-backend

I’ve searched for a while, and i don’t see anything out of the ordinary, im not sure if im missing something or if this is an actual bug since the library is fairly new, eitherway, any help would be much appreciated, and i must say i love it a lot, its so much simple to work with denodb than any other orm i’ve tried so far.

Best regards!

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
ItsJustMeChriscommented, Aug 21, 2020

@Frenzoid I spent a lot of time on this issue and had to pull DenoDB locally to figure it out…

I believe since you’ve gotten id: { primaryKey: true, autoIncrement: true },

It can’t find the type of the primary key, you need to also include id: { primaryKey: true, autoIncrement: true, type: DataTypes.INTEGER },

1reaction
Frenzoidcommented, Jul 16, 2020

Its all good, i’ve never did something as complex and big as an orm so i can only imagine :p, im also a bit noob with deno and i havent touched TS in a while, so if any question sounds noobish, im sorry about it.

So, what i did was the following: I’ve made empty static functions on both User and Survey as the following:

Users.ts:

...
  static surveys() {}
...

Survey.ts:

...
  static user() {}
...

That way, i can rewrite the function logic on the relations file as you suggested for my implementation, where i do the relations after the tables are created:

relations.ts:

// relations.ts: file which contains all relations, executed on server.ts after all models are linked.

import { User } from "../Models/User.ts";
import Survey from "../Models/Survey.ts";

// Execute Relations:
export function SubmitRelations() {
  // User has many Surveys, and a Survey has one User.
  Survey.user = () => Survey.hasOne(User);
  User.surveys = () => User.hasMany(Survey);
}

Everything seems to work fine until now, there’s no loop error anymore! 😄, but for some reason im getting an error when creating the foreign key with userId: Relationships.belongsTo(User) on Survey.ts

error: Uncaught PostgresError: foreign key constraint "surveys_user_id_foreign" cannot be implemented
  return new PostgresError(errorFields);
         ^
    at parseError (error.ts:106:10)
    at Connection._processError (connection.ts:434:19)
    at Connection._simpleQuery (connection.ts:340:22)
    at async Connection.query (connection.ts:546:16)
    at async Client.query (client.ts:25:12)
    at async PostgresConnector.query (postgres-connector.ts:46:22)
    at async Database.query (database.ts:154:21)
    at async Function.createTable (model.ts:120:5)
    at async Database.sync (database.ts:124:7)
    at async server.ts:10:1

The error is being dropped when syncing with the database (server.ts:10:1 being await db.sync({ drop: true });):

server.ts:

...
try {
  await db.sync({ drop: true });
  if (db.getConnector()._connected) {
    console.log("Database synced successfully, creating relations!");
    SubmitRelations();
  }
} catch (e) {
  console.error(e);
}
...
Read more comments on GitHub >

github_iconTop Results From Across the Web

Uncaught ReferenceError: Cannot access 'Model' before ...
Hello, I encountered this error when trying to achieve one-to-many relationship error: Uncaught ReferenceError: Cannot access 'UserModel' before ...
Read more >
ReferenceError: Cannot access 'Model ' before initialization
I am facing an issue in defining the relationship between models in the Nodejs express app. I have two models one is Contact...
Read more >
ReferenceError: can't access lexical declaration 'X' before ...
A lexical variable was accessed before it was initialized. This happens within any block statement, when variables declared with let or const ...
Read more >
referenceerror: cannot access 'main' before initialization
The “cannot access before initialization” reference error occurs in JavaScript when you try to access a variable before it is declared with let...
Read more >
ReferenceError: Cannot access before initialization in JS
The "Cannot access before initialization" error occurs when a variable declared using let or const is accessed before it was initialized in the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found