Skip to content

src/db/db.ts โ€‹

From Week 4 in-class: REST layers ยท original: si-679-f-26-week-04-nyt-jessicadonoho/src/db/db.ts ยท all files in this project

ts
import { MongoClient, ObjectId } from 'mongodb';
import type { Db, Document, InsertOneResult } from 'mongodb';

// Where the database server lives, and which database on it we want.
const MONGO_URI: string = 'mongodb://127.0.0.1:27017';
const DB_NAME: string = 'week4';

// Collection names. The rest of the app asks for db.PRODUCTS rather than
// typing the string 'products' in five different places.
const PRODUCTS: string = 'products';

let mongoClient: MongoClient | null = null;
let theDb: Db;

const init = async (
    uri: string = MONGO_URI,
    dbName: string = DB_NAME
): Promise<void> => {
    mongoClient = new MongoClient(uri);
    await mongoClient.connect();
    theDb = mongoClient.db(dbName);
};

const getAllInCollection = async (
    collectionName: string
): Promise<Document[]> => {
    if (!mongoClient) {
      await init();
    }
    const allDocs = theDb.collection(collectionName).find();
    return await allDocs.toArray();
};

// export const db = {
//     init,
//     getAllInCollection,
//     PRODUCTS
// };

const addToCollection = async (
  collectionName: string,
  docData: Document
): Promise<InsertOneResult> => {
  if (!mongoClient) {
    await init();
  }
  return await theDb.collection(collectionName).insertOne(docData);
};

const getThroughID = async(
    id:string,
    collectionName: string
): Promise<Document | null> => {
    if (!mongoClient){
        await init();
    }
    // FIXED: `new ObjectId(id)` throws if id is not a valid 24-char hex
    // string (e.g. /products/abc), which became a 500 error. Now an invalid
    // id just means "not found", so the controller can send a 404.
    if (!ObjectId.isValid(id)) {
        return null;
    }
    return await theDb.collection(collectionName).findOne({ _id: new ObjectId(id) });

}

const deleteThroughID = async(
  id: string,
  collectionName:string
):Promise<Number | null> => {
  if(!mongoClient){
    await init();
  }
  if (!ObjectId.isValid(id)){
    return null
  }
  const result = await theDb.collection(collectionName).deleteOne({ _id: new ObjectId(id) });
  return result.deletedCount;
}


// Neither of these is for the app. The app connects once at startup and
// then runs until you stop it, so it never needs to hang up or to empty
// a collection. Tests need both.

const disconnect = async (): Promise<void> => {
  if (mongoClient) {
    await mongoClient.close();
    mongoClient = null;
  }
};

// The leading underscore is a convention, not a language feature. It is a
// note to the next reader: this exists for tests, not for the app.
const _clearCollection = async (collectionName: string): Promise<void> => {
  await theDb.collection(collectionName).deleteMany({});
};

export const db = {
  init,
  getAllInCollection,
  addToCollection,
  getThroughID,
  disconnect,
  deleteThroughID,
  _clearCollection,
  PRODUCTS
};