<repo_name>krissukoco/prac-mongodb<file_sep>/playground/mongodb-delete.js
const MongoClient = require('mongodb').MongoClient;

MongoClient.connect('mongodb://localhost:27017/TodoApp', (err, client) => {
  if (err) {
    return console.log('Unable to connect to MongoDB server');
  } // 'return' will prevent codes below to excecute
  console.log('Connection successful');
  const db = client.db('TodoApp'); // For MongoDB v3.x.x

  db.collection('Todos').findOneAndDelete({text: 'Wash car'}).then((result) => {
    console.log(result);
  }, (err) => {
    console.log(err);
  });

  client.close();
});
<file_sep>/server/tests/server.test.js
const expect = require('expect');
const request = require('supertest');
const { ObjectID } = require('mongodb');

const { app } = require('./../server');
const { Todo } = require('./../models/todo');
const { User } = require('./../models/user');

const todosDummy = [{
  _id: new ObjectID(),
  text: 'First todo',
  completed: false,
  completedAt: 123
}, {
  _id: new ObjectID(),
  text: 'Second todo',
  completed: false,
  completedAt: 123
}, {
  _id: new ObjectID(),
  text: 'Third todo',
  completed: false,
  completedAt: 123
}];

// Set Todo to be empty, then insert todosDummy
beforeEach((done) => {
  Todo.remove({}).then(() => {
    Todo.insertMany(todosDummy, function(error, docs) {
      console.log('Before Each: ', docs.length);
    });
  }).then(() => done());
});

// Test POST /todos
describe('POST /todos', () => {
  it('should create a new todo', (done) => {
    var anyText = 'Changed a bit';

    request(app)
      .post('/todos')
      .send({text: anyText}) // required to send a 'text' field (POST)
      .expect(200)
      .expect((res) => {
        expect(res.body.text).toBe(anyText);
        console.log('Res.Body: ', res.body);
      })
      .end((err, res) => {
        if (err) {
          return done(err); // print error
          // 'return' is merely to stop next lines to execute
        }
        // console.log(Todo); OPT
        // Ensure that MongoDB has stored the data
        // With (preset) todos is empty (with beforeEach; line 9)
        // Todo.findOne({text: anyText}).then((todos) => { // returns 'todos' as array of documents
        //   console.log('Todos: ', todos);
        //   expect(todos.length).toBe(1);
        //   console.log('Length: ', todos.length);
        //   expect(todos[0].text).toBe(anyText);
        //   done();
        Todo.find({ text: 'Changed a bit' }, function(err, todos) {
          console.log(todos);
          done();
        });
          // console.log(todos[0].text);
        // }).catch((e) => done(e));
      });
  }); //
  // No returns for bad data
  it('should NOT send a todo with BAD data', (done) => {
    request(app)
      .post('/todos')
      .send({})
      .expect(400)
      .end((err, res) => {
        if(err) {
          console.log('Other error occured');
          return done(err);
        }
        Todo.find().then((todos) => {
          console.log('3 Todos: ', todos);
          expect(todos.length).toBe(3);
          done();
        }).catch((err) => done(err));
      });
  });
});

// Test GET /todos
describe('GET /todos', () => {
  it('should get all todos', (done) => {
    request(app)
      .get('/todos')
      .expect(200)
      .expect((res) => {
        expect(res.body.todos.length).toBe(3);
      })
      .end(done);
  });
});

// Todo with ID
describe('GET /todos/:id', () => {
  it('should return Todo with correct ID', (done) => {
    request(app)
      .get(`/todos/${todosDummy[0]._id.toHexString()}`)
      .expect(200)
      .expect((res) => {
        expect(res.body.todo.text).toBe(todosDummy[0].text);
      })
      .end(done);
  });

  it('should return 404 if Todo NOT FOUND', (done) => {
    // Some Random ID
    var hexId = new ObjectID().toHexString();

    request(app)
      .get(`/todos/${hexId}`)
      .expect(404)
      .expect((res) => {
        expect(res.body).toEqual({});
      })
      .end(done);
  });

  it('should return 404 with INVALID ID', (done) => {
    request(app)
      .get('/todos/123')
      .expect(404)
      .expect((res) => {
        expect(res.body).toEqual({});
      })
      .end(done);
  });
});

// DELETE with ID
describe('DELETE /todos/:id', () => {

  it('should remove a todo', (done) => {
    var idToRemove = todosDummy[0]._id.toHexString();

    request(app)
      .delete(`/todos/${idToRemove}`)
      .expect(200)
      .expect((res) => {
        expect(res.body.todo._id).toBe(idToRemove);
      })
      .end((err, res) => {
        if (err) {
          return done(err);
        }

        Todo.findById(idToRemove).then((todo) => {
          expect(todo).toNotExist();
          done();
        }).catch((e) => done(e));
      });
  });

  it('should return 404 if NOT FOUND', (done) => {
    var hexId = new ObjectID().toHexString();

    request(app)
      .delete(`/todos/${hexId}`)
      .expect(404)
      .expect((res) => {
        expect(res.body).toEqual({});
      })
      .end(done);
  });

  it('should return 404 if object ID INVALID', (done) => {
    request(app)
      .get('/todos/123')
      .expect(404)
      .expect((res) => {
        expect(res.body).toEqual({});
      })
      .end(done);
  });
});

/////////////////////
// PATCHING with ID
describe('PATCH /todos/:id', () => {
  var idToUpdate = todosDummy[0]._id.toHexString();
  var updateReq = {
    text: 'I am updated',
    completed: true
  };

  it('should update with correct queries', (done) => {
    request(app)
      .patch(`/todos/${idToUpdate}`)
      .send(updateReq)
      .expect(200)
      .expect((res) => {
        expect(res.body.todo.text).toBe(updateReq.text);
        expect(res.body.todo.completed).toBe(updateReq.completed);
        // expect(res.body.todo.completedAt).toBe(123); // Why this fails?
      }).end(done);
  });

  it('should remove completedAt when completed is false', (done) => {
    request(app)
      .patch(`/todos/${idToUpdate}`)
      .send({completed: false})
      .expect(200)
      .expect((res) => {
        expect(res.body.todo.completed).toBe(false);
        expect(res.body.todo.completedAt).toBe(null);
      }).end(done);
  });

})
<file_sep>/playground/mongodb-fetch.js
const MongoClient = require('mongodb').MongoClient;

MongoClient.connect('mongodb://localhost:27017/TodoApp', (err, client) => {
  if (err) {
    return console.log('Unable to connect to MongoDB server');
  } // 'return' will prevent codes below to excecute
  console.log('Connection successful');
  const db = client.db('TodoApp'); // For MongoDB v3.x.x

  var searchName = 'Frank'; // Change the searchName
  // Fetch users with compatible searchName
  db.collection('Users')
    .find({name: searchName})
    .toArray()
    .then((user) => {
      console.log('Users found:');
      console.log(JSON.stringify(user, undefined, 2));
    }, (err) => {
      console.log('Unable to find user', err);
  });

  client.close();
});
<file_sep>/server/models/todo.js
const mongoose = require('mongoose');
// Create a new mongoose model
// Named 'Todo', but create a collection with a name 'todos'
var Todo = mongoose.model('Todo', {
  text: {
    type: String,
    required: true,
    minlength: 1,
    trim: true
  },
  completed: {
    type: Boolean,
    default: false
  },
  completedAt: {
    type: Number,
    default: null
  }
});

module.exports = { Todo };

// // Create a new Object with the rules of the Todo model
// var newTodo = new Todo({
//   text: 'Buy foods'
// });
//
// // Saving to the database
// nweTodo.save().then((doc) => {
//   console.log('Todo saved!', doc);
// }, (err) => {
//   console.log('Unable to save todo', err);
// })
