X press publishing can't successfully proceed past step 48

Hello all,

I found the rope ladder over the broken code ravine earlier on in this dungeon and have gathered 49 of the green gems but still have 6 red empty slots. At about step 48 I stopped making progress. I have compared my code with others and changed all sort of minor details to no avail. Perhaps someone can shed some light on my plight?

Test results:

$ npm test

x-press-publishing@1.0.0 test
mocha

listening on port: 8081

Artist Table
√ should exist
√ should have name, date_of_birth, biography, and is_currently_employed columns with appropriate data types
√ should have a required name column
√ should have a required date_of_birth column
√ should have a required biography column
√ is_currently_employed should default to 1

Series Table
√ should exist
√ should have id, name, and description columns with appropriate data types
√ should have a required name column
√ should have a required description column

Issue Table
√ should exist
√ should have id, name, issue_number, publication_date, artist_id, and series_id columns with appropriate data types
√ should have a required name column
√ should have a required name column
√ should have a required issue_number column
√ should have a required publication_date column
√ should have a required artist_id column
√ should have a required series_id column

GET /api/artists
GET /api/artists 200 2.878 ms - 242
√ should return all currently-employed artists
GET /api/artists 200 0.741 ms - 242
√ should return a status code of 200

GET /api/artists/:id
GET /api/artists/2 200 1.060 ms - 127
√ should return the artist with the given ID
GET /api/artists/2 200 0.477 ms - 127
√ should return a 200 status code for valid IDs
GET /api/artists/999 404 0.553 ms - 9
√ should return a 404 status code for invalid IDs

POST /api/artists
POST /api/artists/ 201 4.452 ms - 127
√ should create a valid artist
POST /api/artists/ 201 4.317 ms - 127
√ should return a 201 status code after artist creation
POST /api/artists/ 201 4.166 ms - 127
√ should return the newly-created artist after artist creation
POST /api/artists/ 201 4.255 ms - 127
√ should set new artists as currently-employed by default
POST /api/artists/ 400 0.173 ms - 11
√ should return a 400 status code for invalid artists

PUT /api/artists/:id
PUT /api/artists/1 200 4.572 ms - 135
√ should update the artist with the given ID
PUT /api/artists/1 200 4.285 ms - 135
√ should return a 200 status code after artist update
PUT /api/artists/1 200 4.282 ms - 135
√ should return the updated artist after artist update
PUT /api/artists/1 400 0.614 ms - 11
√ should return a 400 status code for invalid artist updates

DELETE /api/artists/:id
DELETE /api/artists/1 200 4.529 ms - 122
√ should set the artist with the given ID as not currently-employed
DELETE /api/artists/1 200 4.469 ms - 122
√ should return a 200 status code after artist delete
DELETE /api/artists/1 200 4.371 ms - 122
√ should return the deleted artist after artist delete

GET /api/series
GET /api/series 200 0.744 ms - 192
√ should return all series
GET /api/series 200 0.539 ms - 192
√ should return a status code of 200

GET /api/series/:id
GET /api/series/2 200 0.739 ms - 70
√ should return the series with the given ID
GET /api/series/2 200 0.407 ms - 70
√ should return a 200 status code for valid IDs
GET /api/series/999 404 0.445 ms - 9
√ should return a 404 status code for invalid IDs

POST /api/series
POST /api/series/ 201 4.334 ms - 71
√ should create a valid series
POST /api/series/ 201 4.270 ms - 71
√ should return a 201 status code after series creation
POST /api/series/ 201 4.617 ms - 71
√ should return the newly-created series after series creation
POST /api/series/ 400 0.177 ms - 11
√ should return a 400 status code for invalid series

PUT /api/series/:id
PUT /api/series/1 200 4.635 ms - 79
√ should update the series with the given ID
PUT /api/series/1 200 4.255 ms - 79
√ should return a 200 status code after series update
PUT /api/series/1 200 4.566 ms - 79
√ should return the updated series after series update
PUT /api/series/1 400 0.609 ms - 11
√ should return a 400 status code for invalid series updates

DELETE /api/series/:id
DELETE /api/series/1 400 0.936 ms - 11
√ should remove the series with the specified ID from the database if that series has no related issues
1) “before each” hook for “should return a 204 status code after series delete”

GET /api/series/:seriesId/issues
2) “before all” hook for “should return all issues of an existing series”

POST /api/series/:seriesId/issues
3) “before each” hook for “should create a valid issue”

PUT /api/series/:seriesId/issues/:issueId
4) “before each” hook for “should return a 204 status code after series delete”
5) “before each” hook for “should update the issue with the given ID”

DELETE /api/series/:seriesId/issues/:issueId
6) “before each” hook for “should remove the issue with the specified ID from the database”

49 passing (4s)
6 failing

  1. DELETE /api/series/:id
    “before each” hook for “should return a 204 status code after series delete”:
    Uncaught AssertionError: expected { Object (id, name, …) } to not exist
    at Statement. (test\test.js:689:34)

  2. GET /api/series/:seriesId/issues
    “before all” hook for “should return all issues of an existing series”:
    Uncaught Error: SQLITE_BUSY: database is locked

  3. POST /api/series/:seriesId/issues
    “before each” hook for “should create a valid issue”:
    Uncaught Error: SQLITE_CONSTRAINT: UNIQUE constraint failed: Series.id

  4. DELETE /api/series/:id
    “before each” hook for “should return a 204 status code after series delete”:
    Error: done() called multiple times in hook <DELETE /api/series/:id “before each” hook for “should return a 204 status code after series delete”> of file C:\Users\rifac\Documents\Programming projec
    ts\Codecademy projects\capstone-project-1-x-press-publishing\capstone-project-1-x-press-publishing\capstone-project-1-x-press-publishing\test\test.js; in addition, done() received error: [Error: SQLITE_
    CONSTRAINT: UNIQUE constraint failed: Series.id] {
    errno: 19,
    code: ‘SQLITE_CONSTRAINT’
    }

  5. PUT /api/series/:seriesId/issues/:issueId
    “before each” hook for “should update the issue with the given ID”:
    Uncaught Error: SQLITE_BUSY: database is locked

  6. DELETE /api/series/:seriesId/issues/:issueId
    “before each” hook for “should remove the issue with the specified ID from the database”:
    Uncaught Error: SQLITE_BUSY: database is locked

Series:

const express = require('express'); const seriesRouter = express.Router(); const sqlite3 = require('sqlite3'); const db = new sqlite3.Database(process.env.TEST_DATABASE || './database.sqlite'); const issuesRouter = require('./issues.js'); //issues router redirect seriesRouter.use('/:seriesId/issues', issuesRouter); //get routers seriesRouter.get('/', (req, res, next) => { db.all('SELECT * FROM Series;', (err, series) => { if(err) { next(err); }else{ res.status(200).send({series: series}); } }) }) seriesRouter.param('seriesId', (req, res, next, seriesId) => { const values = {$seriesId: seriesId}; db.get(`SELECT * FROM Series WHERE Series.id = $seriesId;`, values, (err, series) => { if(err){ next(err); }else if (series){ req.series = series; next(); }else{ res.sendStatus(404); } }); }); seriesRouter.get('/:seriesId', (req, res, next) => { res.status(200).send({series: req.series}); next(); }) //post routers seriesRouter.post('/', function(req, res, next) { var name = req.body.series.name; var description = req.body.series.description; if(!name || !description){ return res.sendStatus(400); } db.run('INSERT INTO Series (name, description) VALUES ($name, $description);', { $name: name, $description: description }, function(err) { if(err){ next(err); }else{ db.get(`SELECT * FROM Series WHERE id= ${this.lastID};`, function(err, series) { if(err){ next(err); } else{ res.status(201).send({series: series}); next(); }}) }}); }) //put router seriesRouter.put('/:seriesId', (req, res, next) => { var name = req.body.series.name; var description = req.body.series.description; if(!name || !description){ return res.sendStatus(400); } db.run('UPDATE Series SET name = $name, description = $description WHERE id = $seriesId;', { $seriesId: req.params.seriesId, $name: name, $description: description }, function (err){ if(err){ next(err); }else{ db.get(`SELECT * FROM Series WHERE id= ${req.params.seriesId};`, function(err, series) { if(err){ next(err); } else{ res.status(200).send({series: series}); next(); }}) } } );}) //step 53 seriesRouter.delete('/:seriesId', (req, res, next) => { db.all('SELECT * FROM Issue WHERE series_id = $seriesId;', { $seriesId: req.params.seriesId }, (err, series) => { if(err) { next(err); }else if(series){ return res.sendStatus(400); }else{ db.run('DELETE FROM Series WHERE Series.id = $seriesId;', { $seriesId: req.params.seriesId },(err) => { if(err) { next(err); }else{ res.sendStatus(204); } }) } }) }) module.exports = seriesRouter;
const express = require('express'); const issuesRouter = express.Router({mergeParams: true}); const sqlite3 = require('sqlite3'); const db = new sqlite3.Database(process.env.TEST_DATABASE || './database.sqlite'); issuesRouter.param('issueId', (req, res, next, issueId) =>{ db.get('SELECT * FROM Issue WHERE Issue.id = $issueId;', { $issueId: issueId }, (err, id) => { if(err){ next(err); }else if(id){ next(); }else{ return res.sendStatus(404); } }) }) issuesRouter.get('/', (req, res, next) => { values = { $seriesId: req.params.$seriesId }; db.all('SELECT * FROM Issue WHERE Issue.series_id = $seriesId;', values, (err, issues) => { if(err) { next(err); }else{ res.status(200).send({issues: issues}); } }) }) //step 49 issuesRouter.post('/', (req, res, next) => { var name = req.body.issue.name; var issueNumber = req.body.issue.issue_number; var publicationDate = req.body.issue.publication_date; var artistId = req.body.issue.publication_date; if(!name || !issueNumber || !publicationDate || !artistId) { return res.sendStatus(400); } db.get('SELECT * FROM Artist WHERE Artist.id = $artistId', { $artistId: artistId }, (err, artist) => { if(err){ next(err); }else{ if(!artistId) { return res.sendStatus(400); } } }) db.run('INSERT INTO Issue (name, issue_number, publication_date, artist_id, series_id) VALUES ($name, $issueNumber, $publicatonDate, $artistId, $seriesId);', { $name: name, $issueNumber: issue_number, $publicationDate: publicationDate, $artistId: artistId, $seriesId: req.params.seriesId }, function(err) { if(err){ next(err); }else{ db.get(`SELECT * FROM Issue WHERE Issue.id = ${this.lastID};`, function (err, issue){ if(err){ next(err); }else{ res.status(201).send({issue: issue}); } }) } } ) }) issuesRouter.put('/:issueId', (req, res, next) => { var name = req.body.issue.name; var issueNumber = req.body.issue.issue_number; var publicationDate = req.body.issue.publication_date; var artistId = req.body.issue.publication_date; if(!name || !issueNumber || !publicationDate || !artistId) { return res.sendStatus(400); } db.get('SELECT * FROM Artist WHERE Artist.id = $artistId', { $artistId: artistId }, (err, artist) => { if(err){ next(err); }else{ if(!artistId) { return res.sendStatus(400); } } }) db.run('UPDATE Issue SET name = $name, issueNumber = $issueNumber, publication_date = $publicationDate, artist_id = $artistId WHERE id = $issueId;', { $name: name, $issueNumber: issue_number, $publicationDate: publicationDate, $id: req.params.issueId }, function(err) { if(err){ next(err); }else{ db.get(`SELECT * FROM Issue WHERE Issue.id = ${req.params.issueId};`, (err, updatedIssue) => { if(err){ next(err); }else{ res.status(200).send({issue: updatedIssue}); } }) } } ) }) issuesRouter.delete('/:issueId', (req, res, next) => { db.run('DELETE FROM Issue WHERE Issue.id = $issueId;', { $issueId: req.params.issueId }, (err) => { if(err){ next(err); }else{ res.sendStatus(204); } }) }) module.exports = issuesRouter;

migration:

const sqlite3 = require('sqlite3'); const db = new sqlite3.Database('./database.sqlite'); //step 16 create database if it doesn't exist db.run("CREATE TABLE IF NOT EXISTS Artist (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, date_of_birth TEXT NOT NULL, biography TEXT NOT NULL, is_currently_employed INTEGER DEFAULT 1);"); //step 36 create database if it doesn't exist db.run("CREATE TABLE IF NOT EXISTS Series (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, description TEXT NOT NULL);"); //step 45 create database if it doesn't exist db.run("CREATE TABLE IF NOT EXISTS Issue (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, issue_number INTEGER NOT NULL, publication_date TEXT NOT NULL, artist_id INTEGER NOT NULL, series_id INTEGER NOT NULL, FOREIGN KEY (artist_id) REFERENCES Artist(id), FOREIGN KEY(series_id) REFERENCES Series(id));");

Thanks!