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
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Node Dependencies
node_modules/
npm-debug.log

# Compiled TypeScript Output
dist/
build/

# Local SQLite Database (from Problem 5)
app.db
*.db

# Environment Variables
.env

# OS/Editor Generated Files
.DS_Store
.vscode/
28 changes: 28 additions & 0 deletions src/problem4/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Problem 4: Three ways to sum to n

# Overview
This repository contains three unique implementations in TypeScript to calculate the summation of integers from 1 to `n` (e.g., `sum_to_n(5) === 1 + 2 + 3 + 4 + 5 === 15`).

Each implementation explores a different algorithmic approach, varying in time and space complexity.

# Implementation A: Iterative Approach
This approach uses a standard `for` loop to incrementally add each number from 1 to `n` to a running total.

# Implementation B: Mathematical Formula (Optimal)
This approach utilizes the arithmetic progression sum formula: `n * (n + 1) / 2`.

# Implementation C: Recursive Approach
This approach solves the problem by breaking it down into smaller sub-problems, calling itself with `n - 1` until it reaches the base case (`n <= 1`).

## How to Run

Ensure you have [Node.js](https://nodejs.org/) and TypeScript installed.

1. Install dependencies (if testing libraries are configured):
npm install

2. Compile the TypeScript file:
npx tsc src/sum.ts

3. Run tests (assuming Jest is set up from your earlier configurations):
npm test
11 changes: 11 additions & 0 deletions src/problem4/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { createDefaultPreset } = require("ts-jest");

const tsJestTransformCfg = createDefaultPreset().transform;

/** @type {import("jest").Config} **/
module.exports = {
testEnvironment: "node",
transform: {
...tsJestTransformCfg,
},
};
14 changes: 14 additions & 0 deletions src/problem4/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "code-challenge",
"version": "1.0.0",
"scripts": {
"build": "tsc",
"test": "jest"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"jest": "^29.7.0",
"ts-jest": "^29.4.9",
"typescript": "^5.0.0"
}
}
7 changes: 7 additions & 0 deletions src/problem4/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { sum_to_n_a, sum_to_n_b, sum_to_n_c } from "./sum";

const n = 5;

console.log("Iterative:", sum_to_n_a(n));
console.log("Formula:", sum_to_n_b(n));
console.log("Recursive:", sum_to_n_c(n));
25 changes: 25 additions & 0 deletions src/problem4/src/sum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Implementation A: Iterative
export function sum_to_n_a(n: number): number {
if (n < 0) throw new Error("n must be non-negative");

let sum = 0;
for (let i = 1; i <= n; i++) {
sum += i;
}
return sum;
}

// Implementation B: Formula (Optimal)
export function sum_to_n_b(n: number): number {
if (n < 0) throw new Error("n must be non-negative");

return (n * (n + 1)) / 2;
}

// Implementation C: Recursion
export function sum_to_n_c(n: number): number {
if (n < 0) throw new Error("n must be non-negative");
if (n <= 1) return n;

return n + sum_to_n_c(n - 1);
}
18 changes: 18 additions & 0 deletions src/problem4/tests/sum.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { sum_to_n_a, sum_to_n_b, sum_to_n_c } from "../src/sum";

describe("Sum to n", () => {
const testCases = [
{ input: 0, expected: 0 },
{ input: 1, expected: 1 },
{ input: 5, expected: 15 },
{ input: 10, expected: 55 },
];

testCases.forEach(({ input, expected }) => {
test(`n = ${input}`, () => {
expect(sum_to_n_a(input)).toBe(expected);
expect(sum_to_n_b(input)).toBe(expected);
expect(sum_to_n_c(input)).toBe(expected);
});
});
});
11 changes: 11 additions & 0 deletions src/problem4/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"strict": true,
"outDir": "dist",
"esModuleInterop": true,
"types": ["jest"]
},
"include": ["src", "tests"]
}
78 changes: 78 additions & 0 deletions src/problem5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Problem 5: A Crude Server

This is a backend RESTful API built with ExpressJS and TypeScript. It implements a set of CRUD interfaces for a generic "Resource" entity and uses a local SQLite database for simple, reliable data persistence.

## Prerequisites

- [Node.js](https://nodejs.org/) (v14 or higher recommended)
- npm or yarn

## Setup and Configuration

1. **Install dependencies:**
Navigate to the project root and run:
```bash
npm init -y
npm install express better-sqlite3
npm install --save-dev typescript @types/express @types/node @types/better-sqlite3 ts-node nodemon
```

2. **Database:**
This application uses `better-sqlite3`. Upon starting the server for the first time, an `app.db` SQLite file will be automatically generated in the root directory. The database tables will be created automatically if they do not exist.

## How to Run the Application

**Development Mode (with auto-reload):**
```bash
npm run dev
```

**Production Mode:**
```bash
npm run build
npm start
```

The server will start on **http://localhost:3000**.

## Testing with Postman

You can use API testing tools like [Postman](https://www.postman.com/) or the VS Code REST Client to interact with the server. Ensure the server is running locally on port 3000 before sending requests.

### 1. Create a Resource
- **Method:** `POST`
- **URL:** `http://localhost:3000/resources`
- **Headers:** `Content-Type: application/json`
- **Body (raw JSON):**
```json
{
"name": "Sample Resource",
"description": "This is a test",
"status": "active"
}
```

### 2. List Resources
- **Method:** `GET`
- **URL:** `http://localhost:3000/resources`
- **Query Filters (Optional):** You can filter by status using `?status=active` or `?status=inactive` (e.g., `http://localhost:3000/resources?status=active`).

### 3. Get Details of a Resource
- **Method:** `GET`
- **URL:** `http://localhost:3000/resources/1` *(Replace '1' with the ID of an existing resource)*

### 4. Update Resource Details
- **Method:** `PUT`
- **URL:** `http://localhost:3000/resources/1`
- **Headers:** `Content-Type: application/json`
- **Body (raw JSON):**
```json
{
"name": "Updated Name",
"status": "inactive"
}
```

### 5. Delete a Resource
- **Method:** `DELETE`
- **URL:** `http://localhost:3000/resources/1`
28 changes: 28 additions & 0 deletions src/problem5/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "problem-5",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node --loader ts-node/esm src/index.ts",
"dev": "nodemon --exec node --loader ts-node/esm src/index.ts",
"build": "tsc"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "This is a backend RESTful API built with ExpressJS and TypeScript. It implements a set of CRUD interfaces for a generic \"Resource\" entity and uses a local SQLite database for simple, reliable data persistence.",
"dependencies": {
"better-sqlite3": "^11.10.0",
"express": "^5.2.1"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.13",
"@types/express": "^5.0.6",
"@types/node": "^25.6.0",
"nodemon": "^3.1.14",
"ts-node": "^10.9.2",
"typescript": "^6.0.3"
}
}
119 changes: 119 additions & 0 deletions src/problem5/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// src/index.ts
import express, { type Request, type Response } from 'express';
import Database from 'better-sqlite3';

const app = express();
const port = process.env.PORT || 3000;

// Middleware
app.use(express.json());

// Initialize SQLite Database (creates 'app.db' file in the root)
const db = new Database('app.db', { verbose: console.log });

// Create the table if it doesn't exist
db.exec(`
CREATE TABLE IF NOT EXISTS resources (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT,
status TEXT DEFAULT 'active'
)
`);

// Prepared Statements for performance and security
const insertResource = db.prepare('INSERT INTO resources (name, description, status) VALUES (?, ?, ?)');
const selectAllResources = db.prepare('SELECT * FROM resources');
const selectResourcesByStatus = db.prepare('SELECT * FROM resources WHERE status = ?');
const selectResourceById = db.prepare('SELECT * FROM resources WHERE id = ?');
const updateResource = db.prepare('UPDATE resources SET name = ?, description = ?, status = ? WHERE id = ?');
const deleteResource = db.prepare('DELETE FROM resources WHERE id = ?');

// 1. Create a resource
app.post('/resources', (req: Request, res: Response) => {
const { name, description, status } = req.body;
if (!name) {
return res.status(400).json({ error: 'Name is required' });
}

try {
const info = insertResource.run(name, description || null, status || 'active');
res.status(201).json({ id: info.lastInsertRowid, name, description, status });
} catch (error) {
res.status(500).json({ error: 'Failed to create resource' });
}
});

// 2. List resources with basic filters (e.g., ?status=active)
app.get('/resources', (req: Request, res: Response) => {
const { status } = req.query;

try {
let resources;
if (status && typeof status === 'string') {
resources = selectResourcesByStatus.all(status);
} else {
resources = selectAllResources.all();
}
res.status(200).json(resources);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch resources' });
}
});

// 3. Get details of a resource
app.get('/resources/:id', (req: Request, res: Response) => {
const { id } = req.params;

try {
const resource = selectResourceById.get(id);
if (!resource) {
return res.status(404).json({ error: 'Resource not found' });
}
res.status(200).json(resource);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch resource' });
}
});

// 4. Update resource details
app.put('/resources/:id', (req: Request, res: Response) => {
const { id } = req.params;
const { name, description, status } = req.body;

try {
const existing = selectResourceById.get(id) as any;
if (!existing) {
return res.status(404).json({ error: 'Resource not found' });
}

const updatedName = name !== undefined ? name : existing.name;
const updatedDesc = description !== undefined ? description : existing.description;
const updatedStatus = status !== undefined ? status : existing.status;

updateResource.run(updatedName, updatedDesc, updatedStatus, id);
res.status(200).json({ id: Number(id), name: updatedName, description: updatedDesc, status: updatedStatus });
} catch (error) {
res.status(500).json({ error: 'Failed to update resource' });
}
});

// 5. Delete a resource
app.delete('/resources/:id', (req: Request, res: Response) => {
const { id } = req.params;

try {
const info = deleteResource.run(id);
if (info.changes === 0) {
return res.status(404).json({ error: 'Resource not found' });
}
res.status(204).send(); // 204 No Content
} catch (error) {
res.status(500).json({ error: 'Failed to delete resource' });
}
});

// Start Server
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
Loading