Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
.env
coverage/
package-lock.json
19 changes: 19 additions & 0 deletions src/problem4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Problem 4: Three Ways to Sum to n

This folder provides three unique TypeScript implementations of `sum_to_n`.

## Implementations

- `sum_to_n_a`: iterative loop, simple and explicit, `O(|n|)` time and `O(1)` space.
- `sum_to_n_b`: arithmetic-series formula, fastest option at `O(1)` time and `O(1)` space.
- `sum_to_n_c`: recursive implementation, valid but less efficient because it uses `O(|n|)` stack space.

For negative numbers, the functions sum from `0` down to `n` so the behavior stays deterministic for any integer input.

## Test

```bash
cd src/problem4
npm install
npm test
```
15 changes: 15 additions & 0 deletions src/problem4/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "problem4",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"test": "node --import tsx --test ./test/sum-to-n.test.ts",
"build": "tsc -p tsconfig.json"
},
"devDependencies": {
"@types/node": "^24.6.0",
"tsx": "^4.20.6",
"typescript": "^5.9.3"
}
}
43 changes: 43 additions & 0 deletions src/problem4/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export function sum_to_n_a(n: number): number {
// Iterative approach: O(|n|) time, O(1) space.
let total = 0;

if (n >= 0) {
for (let value = 1; value <= n; value += 1) {
total += value;
}

return total;
}

for (let value = 0; value >= n; value -= 1) {
total += value;
}

return total;
}

export function sum_to_n_b(n: number): number {
// Closed-form arithmetic series: O(1) time, O(1) space.
if (n >= 0) {
return (n * (n + 1)) / 2;
}

return (Math.abs(n) * (n - 1)) / 2;
}

export function sum_to_n_c(n: number): number {
// Recursive walk: O(|n|) time, O(|n|) call stack space.
const step = n >= 0 ? 1 : -1;
const stop = n >= 0 ? n + 1 : n - 1;

const walk = (current: number, total: number): number => {
if (current === stop) {
return total;
}

return walk(current + step, total + current);
};

return walk(step > 0 ? 1 : 0, 0);
}
20 changes: 20 additions & 0 deletions src/problem4/test/sum-to-n.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import assert from "node:assert/strict";
import test from "node:test";

import { sum_to_n_a, sum_to_n_b, sum_to_n_c } from "../src/index.js";

const cases = [
{ input: 0, expected: 0 },
{ input: 1, expected: 1 },
{ input: 5, expected: 15 },
{ input: -3, expected: -6 },
{ input: 10, expected: 55 }
] as const;

for (const fn of [sum_to_n_a, sum_to_n_b, sum_to_n_c]) {
test(`${fn.name} returns the expected summation`, () => {
for (const { input, expected } of cases) {
assert.equal(fn(input), expected);
}
});
}
17 changes: 17 additions & 0 deletions src/problem4/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"declaration": true,
"outDir": "dist",
"rootDir": ".",
"esModuleInterop": true,
"skipLibCheck": true
},
"include": [
"src/**/*.ts",
"test/**/*.ts"
]
}
3 changes: 3 additions & 0 deletions src/problem5/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
PORT=3000
MONGODB_URI=mongodb://127.0.0.1:27017/code_challenge_problem5
AUTH_TOKEN=replace-with-a-strong-token
223 changes: 223 additions & 0 deletions src/problem5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
# Problem 5: A Crude Server

A RESTful CRUD API server built with Express.js and TypeScript, using MongoDB for persistence and Bearer token authentication for protected endpoints.

## Features

- CRUD operations for resource creation, listing, detail lookup, update, and deletion.
- Basic filtering with `name` and `status` query parameters.
- MongoDB persistence through Mongoose.
- Bearer token authentication controlled by environment configuration.
- Interactive Swagger/OpenAPI documentation for browser-based testing.
- TypeScript-based codebase with integration tests for the API flow.

## Tech Stack

- **Runtime**: Node.js
- **Framework**: Express.js
- **Language**: TypeScript
- **Database**: MongoDB with Mongoose
- **Documentation**: Swagger/OpenAPI 3.0 with Swagger UI
- **Testing**: Node test runner, Supertest, mongodb-memory-server

## Resource Model

```json
{
"id": "ObjectId",
"name": "Test Resource",
"value": "xxxxx",
"description": "A test resource",
"status": 1,
"createdAt": "2026-01-25T10:00:00.000Z",
"updatedAt": "2026-01-25T10:00:00.000Z",
"detail": {}
}
```

## Endpoints

- `POST /resources` creates a resource.
- `GET /resources?name=abc&status=1` lists resources with basic filters.
- `GET /resources/:id` returns a resource detail.
- `PUT /resources/:id` updates a resource.
- `DELETE /resources/:id` deletes a resource.

All endpoints require `Authorization: Bearer <AUTH_TOKEN>`.

## Installation

1. Move into the problem folder:

```bash
cd src/problem5
```

2. Install dependencies:

```bash
npm install
```

3. Copy the environment file:

```bash
cp .env.example .env
```

4. Update the values in `.env`:

```env
PORT=3000
MONGODB_URI=mongodb://127.0.0.1:27017/code_challenge_problem5
AUTH_TOKEN=replace-with-a-strong-token
```

## Running the Application

### Development Mode

```bash
npm run dev
```

### Production Build

```bash
npm run build
```

If you want to start the compiled output manually:

```bash
node dist/src/server.js
```

The server starts on `http://localhost:3000` by default.

## API Documentation

### Swagger UI

Once the server is running, open:

- [http://localhost:3000/api-docs](http://localhost:3000/api-docs)

Swagger is public for convenience, but the actual CRUD endpoints still require Bearer authentication.

How to test in Swagger UI:

1. Open the Swagger page.
2. Expand any `/resources` endpoint.
3. Click `Authorize`.
4. Enter the token as plain text from `AUTH_TOKEN`.
5. Run requests directly from the browser.

Useful supporting endpoint:

- [http://localhost:3000/openapi.json](http://localhost:3000/openapi.json) exposes the raw OpenAPI document.

## API Endpoints

- `POST /resources` creates a resource.
- `GET /resources?name=abc&status=1` lists resources with basic filters.
- `GET /resources/:id` returns a resource detail.
- `PUT /resources/:id` updates a resource.
- `DELETE /resources/:id` deletes a resource.

## Testing with cURL

All examples below assume:

```bash
set TOKEN=replace-with-a-strong-token
```

If you are using PowerShell, use:

```powershell
$TOKEN = "replace-with-a-strong-token"
```

### 1. Create a resource

```bash
curl -X POST http://localhost:3000/resources \
-H "Authorization: Bearer %TOKEN%" \
-H "Content-Type: application/json" \
-d "{\"name\":\"Test Resource\",\"value\":\"xxxxx\",\"description\":\"A test resource\",\"status\":1,\"detail\":{\"source\":\"curl\"}}"
```

PowerShell example:

```powershell
curl.exe -X POST http://localhost:3000/resources `
-H "Authorization: Bearer $TOKEN" `
-H "Content-Type: application/json" `
-d "{\"name\":\"Test Resource\",\"value\":\"xxxxx\",\"description\":\"A test resource\",\"status\":1,\"detail\":{\"source\":\"powershell\"}}"
```

### 2. List resources

```bash
curl "http://localhost:3000/resources?name=Test&status=1" \
-H "Authorization: Bearer %TOKEN%"
```

### 3. Get resource detail

```bash
curl http://localhost:3000/resources/<resource_id> \
-H "Authorization: Bearer %TOKEN%"
```

### 4. Update a resource

```bash
curl -X PUT http://localhost:3000/resources/<resource_id> \
-H "Authorization: Bearer %TOKEN%" \
-H "Content-Type: application/json" \
-d "{\"description\":\"Updated description\",\"status\":0}"
```

### 5. Delete a resource

```bash
curl -X DELETE http://localhost:3000/resources/<resource_id> \
-H "Authorization: Bearer %TOKEN%"
```

## Test

```bash
npm test
```

## Project Structure

```text
src/problem5/
├── src/
│ ├── config/
│ │ ├── database.ts
│ │ ├── env.ts
│ │ └── swagger.ts
│ ├── controllers/
│ │ └── resource-controller.ts
│ ├── middleware/
│ │ └── auth.ts
│ ├── models/
│ │ └── resource.ts
│ ├── routes/
│ │ └── resource-routes.ts
│ ├── types/
│ │ └── express.d.ts
│ ├── app.ts
│ └── server.ts
├── test/
│ └── resource-api.test.ts
├── .env.example
├── package.json
├── tsconfig.json
└── README.md
```
29 changes: 29 additions & 0 deletions src/problem5/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "problem5",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "tsx watch src/server.ts",
"test": "node --import tsx --test ./test/resource-api.test.ts",
"build": "tsc -p tsconfig.json"
},
"dependencies": {
"dotenv": "^17.2.3",
"express": "^5.1.0",
"mongoose": "^8.19.1",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1"
},
"devDependencies": {
"@types/express": "^5.0.3",
"@types/node": "^24.6.0",
"@types/supertest": "^6.0.3",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.8",
"mongodb-memory-server": "^10.2.3",
"supertest": "^7.1.4",
"tsx": "^4.20.6",
"typescript": "^5.9.3"
}
}
Loading