Compare commits

..

10 commits

Author SHA1 Message Date
Pablo Martin
b839aeba78 completed exercise 4.7 2025-06-05 15:48:19 +02:00
Pablo Martin
e51f318929 exercise 4.6 completed 2025-06-05 15:44:55 +02:00
0309a2cc95
completed 4.5 2025-06-04 23:59:57 +02:00
160402f147
completed 4.4 2025-06-04 23:47:43 +02:00
a41907fe4b
exercise 4.3 completed 2025-06-04 23:35:31 +02:00
Pablo Martin
9bd54f4719 follow along with tests 2025-06-04 17:58:33 +02:00
Pablo Martin
f58ef53347 completed 2025-06-04 17:52:14 +02:00
Pablo Martin
0d97a86ac8 more refactor 2025-06-04 17:49:14 +02:00
Pablo Martin
09a320a5da refactor 2025-06-04 17:44:52 +02:00
Pablo Martin
41ec39c961 extract db 2025-06-04 17:25:35 +02:00
13 changed files with 387 additions and 34 deletions

View file

@ -5,7 +5,7 @@
"scripts": {
"start": "node src/app.js",
"dev": "node --watch src/app.js",
"test": "echo \"Error: no test specified\" && exit 1"
"test": "node --test"
},
"author": "",
"license": "ISC",

View file

@ -1,37 +1,12 @@
const express = require('express')
const mongoose = require('mongoose')
const express = require("express");
const { addRoutes } = require("./routes");
const app = express();
const app = express()
app.use(express.json());
const blogSchema = mongoose.Schema({
title: String,
author: String,
url: String,
likes: Number,
})
addRoutes(app);
const Blog = mongoose.model('Blog', blogSchema)
const mongoUrl = 'mongodb://localhost/bloglist'
mongoose.connect(mongoUrl)
app.use(express.json())
app.get('/api/blogs', (request, response) => {
Blog.find({}).then((blogs) => {
response.json(blogs)
})
})
app.post('/api/blogs', (request, response) => {
const blog = new Blog(request.body)
blog.save().then((result) => {
response.status(201).json(result)
})
})
const PORT = 3003
const PORT = 3003;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`)
})
console.log(`Server running on port ${PORT}`);
});

15
parts/4/blogApp/src/db.js Normal file
View file

@ -0,0 +1,15 @@
const mongoose = require('mongoose')
const blogSchema = mongoose.Schema({
title: String,
author: String,
url: String,
likes: Number,
})
const Blog = mongoose.model('Blog', blogSchema)
const mongoUrl = 'mongodb://localhost/bloglist'
mongoose.connect(mongoUrl)
module.exports = {models: {Blog}}

View file

@ -0,0 +1,22 @@
const { models } = require("./db");
const Blog = models.Blog;
BASE_API_PATH = "/api";
const addRoutes = (app) => {
app.get(`${BASE_API_PATH}/blogs`, (request, response) => {
Blog.find({}).then((blogs) => {
response.json(blogs);
});
});
app.post(`${BASE_API_PATH}/blogs`, (request, response) => {
const blog = new Blog(request.body);
blog.save().then((result) => {
response.status(201).json(result);
});
});
};
module.exports = { addRoutes };

View file

@ -0,0 +1,89 @@
const reverse = (string) => {
return string.split("").reverse().join("");
};
const average = (array) => {
const reducer = (sum, item) => {
return sum + item;
};
return array.length === 0 ? 0 : array.reduce(reducer, 0) / array.length;
};
const listHelper = (posts) => {
console.log("lol");
return 1;
};
const totalLikes = (posts) => {
if (!posts) {
return 0;
}
const likeCount = posts
.map((post) => post.likes)
.reduce((cum, value) => cum + value, 0);
return likeCount;
};
const favoritePost = (posts) => {
if (!posts || posts.length === 0) {
return null;
}
const highestLikes = posts.reduce(
(max, post) => (post.likes > max ? (max = post.likes) : max),
0
);
const favoritePost = posts.find((post) => post.likes == highestLikes);
return favoritePost;
};
const mostPosts = (posts) => {
if (!posts || posts.length === 0) {
return null;
}
const countMap = posts.reduce((acc, post) => {
acc[post.author] = (acc[post.author] || 0) + 1;
return acc;
}, {});
const [author, postsCount] = Object.entries(countMap).reduce(
(max, entry) => (entry[1] > max[1] ? entry : max),
['', 0]
);
return { author, posts: postsCount };
};
const mostLikes = (posts) => {
if (!posts || posts.length === 0) {
return null;
}
const likesMap = posts.reduce((acc, post) => {
acc[post.author] = (acc[post.author] || 0) + post.likes;
return acc;
}, {});
const [author, likesCount] = Object.entries(likesMap).reduce(
(max, entry) => (entry[1] > max[1] ? entry : max),
['', 0]
);
return { author, likes: likesCount };
};
module.exports = {
reverse,
average,
listHelper,
totalLikes,
favoritePost,
mostPosts,
mostLikes
};

View file

@ -0,0 +1,18 @@
const { test, describe } = require('node:test')
const assert = require('node:assert')
const average = require('../src/utils').average
describe('average', () => {
test('of one value is the value itself', () => {
assert.strictEqual(average([1]), 1)
})
test('of many is calculated right', () => {
assert.strictEqual(average([1, 2, 3, 4, 5, 6]), 3.5)
})
test('of empty array is zero', () => {
assert.strictEqual(average([]), 0)
})
})

View file

@ -0,0 +1,43 @@
const { test, describe } = require("node:test");
const assert = require("node:assert");
const { favoritePost } = require("../src/utils");
describe("favoritePost ", () => {
const posts = [
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 5,
__v: 0,
},
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 2,
__v: 0,
},
];
const emptyArray = [];
const gibberish = "asdaSd123asd";
test("finds top properly", () => {
assert.strictEqual(favoritePost(posts), posts[0]);
});
test("works fine with empty array", () => {
assert.strictEqual(favoritePost(emptyArray), null);
});
test("fails with gibberish input", () => {
const failedCall = () => {
favoritePost(gibberish);
};
assert.throws(failedCall, Error);
});
});

View file

@ -0,0 +1,10 @@
const { test, describe } = require("node:test");
const assert = require("node:assert");
const { listHelper } = require("../src/utils");
test("dummy returns one", () => {
const blogs = [];
const result = listHelper(blogs);
assert.strictEqual(result, 1);
});

View file

@ -0,0 +1,54 @@
const { test, describe } = require("node:test");
const assert = require("node:assert");
const { mostLikes } = require("../src/utils");
describe("most likes ", () => {
const posts = [
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 5,
__v: 0,
},
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 2,
__v: 0,
},
{
_id: "123",
title: "Lololo",
author: "John Doe",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 1,
__v: 0,
},
];
const emptyArray = [];
const gibberish = "asdaSd123asd";
test("finds top author properly", () => {
assert.deepStrictEqual(mostLikes(posts), {
author: "Edsger W. Dijkstra",
likes: 7,
});
});
test("works fine with empty array", () => {
assert.strictEqual(mostLikes(emptyArray), null);
});
test("fails with gibberish input", () => {
const failedCall = () => {
mostLikes(gibberish);
};
assert.throws(failedCall, Error);
});
});

View file

@ -0,0 +1,54 @@
const { test, describe } = require("node:test");
const assert = require("node:assert");
const { mostPosts } = require("../src/utils");
describe("most posts ", () => {
const posts = [
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 5,
__v: 0,
},
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 2,
__v: 0,
},
{
_id: "123",
title: "Lololo",
author: "John Doe",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 1,
__v: 0,
},
];
const emptyArray = [];
const gibberish = "asdaSd123asd";
test("finds top author properly", () => {
assert.deepStrictEqual(mostPosts(posts), {
author: "Edsger W. Dijkstra",
posts: 2,
});
});
test("works fine with empty array", () => {
assert.strictEqual(mostPosts(emptyArray), null);
});
test("fails with gibberish input", () => {
const failedCall = () => {
mostPosts(gibberish);
};
assert.throws(failedCall, Error);
});
});

View file

@ -0,0 +1,22 @@
const { test } = require('node:test')
const assert = require('node:assert')
const reverse = require('../src/utils.js').reverse
test('reverse of a', () => {
const result = reverse('a')
assert.strictEqual(result, 'a')
})
test('reverse of react', () => {
const result = reverse('react')
assert.strictEqual(result, 'tcaer')
})
test('reverse of saippuakauppias', () => {
const result = reverse('saippuakauppias')
assert.strictEqual(result, 'saippuakauppias')
})

View file

@ -0,0 +1,43 @@
const { test, describe } = require("node:test");
const assert = require("node:assert");
const { totalLikes } = require("../src/utils");
describe("total likes ", () => {
const posts = [
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 5,
__v: 0,
},
{
_id: "5a422aa71b54a676234d17f8",
title: "Go To Statement Considered Harmful",
author: "Edsger W. Dijkstra",
url: "https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf",
likes: 2,
__v: 0,
},
];
const emptyArray = [];
const gibberish = "asdaSd123asd";
test("counts likes properly", () => {
assert.strictEqual(totalLikes(posts), 7);
});
test("works fine with empty array", () => {
assert.strictEqual(totalLikes(emptyArray), 0);
});
test("fails with gibberish input", () => {
const failedCall = () => {
totalLikes(gibberish);
};
assert.throws(failedCall, Error);
});
});

8
parts/4/notes.md Normal file
View file

@ -0,0 +1,8 @@
Exercises:
* [X] 4.1
* [X] 4.2
* [X] 4.3
* [X] 4.4
* [X] 4.5
* [X] 4.6
* [X] 4.7