deepkit-framework
                                
                                 deepkit-framework copied to clipboard
                                
                                    deepkit-framework copied to clipboard
                            
                            
                            
                        [ORM] MongoDB 5.x connection error
Docker compose
version: '3.1'
services:
  mongo:
    image: mongo:5.0.10
    restart: always
    ports:
      - 27017:27017
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: root
      MONGO_INITDB_DATABASE: db
    volumes:
      - ./db/data:/data/db
      - ./db/config:/data/configdb
#      - ./db/001_users.js:/docker-entrypoint-initdb.d/001_users.js:ro # this just configure a new user
  mongo-express:
    image: mongo-express:1.0.0-alpha.4
    restart: always
    ports:
      - 8081:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: root
      ME_CONFIG_MONGODB_URL: "mongodb://root:root@mongo:27017/"
code
export class BaseEntity {
  id: MongoId & PrimaryKey = '';
  created: Date = new Date;
  updated: Date = new Date;
  static from(data:any){
    const entity = new this();
    for(const k in data){
      entity[k] = data[k];
    }
    return entity;
  }
}
    async function test(){
      @entity.name('user')
      class User extends BaseEntity{
        name:string;
      }
      const database = new Database(new MongoDatabaseAdapter(`mongodb://${"climbo"}:${"climbo"}@${"localhost"}:${27017}/${"climbo"}`), [BaseEntity,User]);
      // database.entityRegistry.add(BaseEntity)
      // database.entityRegistry.add(User);
      await database.migrate(); //create tables
      //await database.persist(new BaseEntity()); //insert data
      await database.persist(User.from({name:'test'})); //insert data
      const allUsers = await database.query(User).find();
      console.log('all users', allUsers);
    }
    test();
crash
/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/command/command.ts:85
                this.current.reject(new MongoError(message.errmsg || 'error', message.code));
                                    ^
MongoError: error
    at HandshakeCommand.handleResponse (/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/command/command.ts:85:37)
    at MongoConnection.onResponse (/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/connection.ts:365:34)
    at ResponseParser.feed (/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/connection.ts:522:22)
    at Socket.<anonymous> (/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/connection.ts:301:66)
    at Socket.emit (node:events:520:28)
    at addChunk (node:internal/streams/readable:315:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at Socket.Readable.push (node:internal/streams/readable:228:10)
    at TCP.onStreamRead (node:internal/stream_base_commons:190:23)
    at TCP.callbackTrampoline (node:internal/async_hooks:130:17)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Sha256ScramAuth.auth (/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/command/auth/scram.ts:103:31)
    at async HandshakeCommand.doAuth (/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/command/handshake.ts:126:9)
    at async HandshakeCommand.execute (/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/command/handshake.ts:115:13)
    at async MongoConnection.execute (/home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/connection.ts:387:20)
    at async /home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/mongo/src/client/connection.ts:458:17
    at async /home/cristian/IdeaProjects/climbo2/node_modules/@deepkit/core/src/core.ts:506:17
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  code: undefined
}
command.ts
message has no ok
so i patched the file locally "ok" in message && !message.ok
    handleResponse(response: Uint8Array): void {
        if (!this.current) throw new Error('Got handleResponse without active command');
        const deserializer: BSONDeserializer<BaseResponse> = this.current.responseType ? getBSONDeserializer(mongoBinarySerializer, this.current.responseType) : deserializeBSONWithoutOptimiser;
        try {
            const message = deserializer(response);
            const error = handleErrorResponse(message);
            if (error) {
                this.current.reject(error);
                return;
            }
            if ("ok" in message && !message.ok) {
                this.current.reject(new MongoError(message.errmsg || 'error', message.code));
            } else {
                this.current.resolve(message);
            }
        } catch (error: any) {
            if (error instanceof ValidationError || error instanceof SerializationError) {
                if (this.current.responseType) {
                    const raw = deserializeBSONWithoutOptimiser(response);
                    console.log('mongo raw response', inspect(raw, {depth: null}));
                    if (raw.errmsg && raw.ok === 0) {
                        const error = handleErrorResponse(raw);
                        if (error) {
                            this.current.reject(error);
                            return;
                        }
                    }
                    this.current.reject(new MongoError(`Could not deserialize type ${stringifyType(this.current.responseType)}: ${error}`));
                    return;
                }
            }
            this.current.reject(error);
        }
    }
PS: the following is broken because of webpack #351
PrimaryKey is still not working
Problem 2) Maybe i discover another bug with the PrimaryKey? if i change id to _id everything works as expected.
export class BaseEntity {
  id: MongoId & PrimaryKey = "507f1f77bcf86cd799439011";
  created: Date = new Date;
  updated: Date = new Date;
  static from(data:any){
    const entity = new this();
    for(const k in data){
      entity[k] = data[k];
    }
    return entity;
  }
}
PrimaryKey is ignored?

It seems so, if i change the definition to
export class BaseEntity {
  id: MongoId & PrimaryKey; // no initializer
  created: Date = new Date;
  updated: Date = new Date;
  static from(data:any){
    const entity = new this();
    for(const k in data){
      entity[k] = data[k];
    }
    return entity;
  }
}
and run a query

@marcj ok i found the problem:
SaslStartResponse, IsMasterResponse has no field ok
so this check fails
            if (!message.ok) {
                this.current.reject(new error_1.MongoError(message.errmsg || 'error', message.code));
            }
            else {
                this.current.resolve(message);
            }
Not sure how to fix this.
            const tname = this.current.responseType?.typeName;
            if ((tname === 'SaslStartResponse' || tname === 'IsMasterResponse') && !("ok" in message)) {
              this.current.resolve(message);
              return;
            }
I tested your code (with some adjustments/fixes) on exactly the same mongo version via Docker and everything worked fine:
    class BaseEntity {
        _id: MongoId & PrimaryKey = '';
        created: Date = new Date;
        updated: Date = new Date;
        static from<T extends typeof BaseEntity>(this: T, data: Partial<InstanceType<T>>): InstanceType<T> {
            return Object.assign(new this, data) as InstanceType<T>;
        }
    }
    @entity.name('user')
    class User extends BaseEntity {
        name!: string;
    }
    const database = new Database(new MongoDatabaseAdapter(`mongodb://localhost:27017/testing`), [User]);
    await database.migrate();
    await database.query(User).deleteMany();
    const u: User = User.from({ name: 'test' });
    await database.persist(u);
    const allUsers = await database.query(User).find();
    expect(allUsers.length).toBe(1);
    expect(allUsers[0]).not.toBe('');
    expect(allUsers[0]).not.toBeUndefined();
    expect(allUsers[0]).toMatchObject({
        name: 'test'
    });
Having id: MongoId & PrimaryKey = "507f1f77bcf86cd799439011"; works for me too. Although there is an issue with deleting when you have entries in the collection where no id field exists, then it throws an error due to incompatible schemas.
@marcj
I see, but you have to try with authentication:
version: '3.1'
services:
  mongo:
    image: mongo:5.0.10
    restart: always
    ports:
      - 27017:27017
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: root
      MONGO_INITDB_DATABASE: root-db
    volumes:
      - ./tmp:/data/db
      - ./tmp:/data/configdb
      - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
mongo-init.js
print('START #################################################################');
var list = ["db"];
for(var i = 0; i < list.length; i++) {
  var name = list[i];
  db = db.getSiblingDB(name);
  db.createUser(
    {
      user: 'user',
      pwd: 'password',
      roles: [{ role: 'readWrite', db: name }],
    },
  );
}
print('END #################################################################');
then in your code
const database = new Database(new MongoDatabaseAdapter(`mongodb://user:password@localhost:27017/db`), [User]);
ps: i think you can create an user without using the mongo-init.js initializer, just try connecting with username & password
@CristianPi thanks, that was the missing piece. Fixed in https://github.com/deepkit/deepkit-framework/commit/c1d6c415199804d966ce17ceb235a050de011da3