Skip to content

Commit

Permalink
Merge pull request #12 from jordan-dalby/arm-support
Browse files Browse the repository at this point in the history
Added arm support
  • Loading branch information
jordan-dalby authored Oct 28, 2024
2 parents db73b99 + 21be89b commit 5e3e764
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 86 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,18 @@ jobs:
id: docker_tag
run: echo "TAG=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }}" >> $GITHUB_ENV

- name: Set up QEMU for cross-platform builds
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
install: true

- name: Build and Push Docker image for Testing
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ env.TAG }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
tags: ${{ env.TAG }}
9 changes: 9 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,20 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up QEMU for cross-platform builds
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
install: true

- name: Build and Push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
platforms: linux/amd64,linux/arm64,linux/arm/v7
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.release.tag_name }}
16 changes: 13 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@
"license": "ISC",
"description": "",
"dependencies": {
"better-sqlite3": "^11.5.0",
"body-parser": "^1.20.3",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.1",
"openai": "^4.67.3",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.7"
"openai": "^4.67.3"
},
"devDependencies": {
"jest": "^29.7.0",
Expand Down
23 changes: 11 additions & 12 deletions server/src/config/database.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const sqlite3 = require('sqlite3');
const { open } = require('sqlite');
const Database = require('better-sqlite3');
const path = require('path');
const fs = require('fs');

Expand All @@ -23,21 +22,23 @@ function getDatabasePath() {
}
}

async function initializeDatabase() {
function initializeDatabase() {
try {
const dbPath = getDatabasePath();
console.log(`Initializing SQLite database at: ${dbPath}`);

db = await open({
filename: dbPath,
driver: sqlite3.Database
// Open database with WAL mode for better performance
db = new Database(dbPath, {
verbose: console.log,
fileMustExist: false
});

// Enable foreign keys
await db.run('PRAGMA foreign_keys = ON');
// Enable foreign keys and WAL mode
db.pragma('foreign_keys = ON');
db.pragma('journal_mode = WAL');

// Create snippets table with timestamp
await db.exec(`
db.exec(`
CREATE TABLE IF NOT EXISTS snippets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
Expand All @@ -61,12 +62,11 @@ async function createBackup() {
const dbPath = getDatabasePath();
const backupPath = getBackupPath();

// Check if source database exists
if (!fs.existsSync(dbPath)) {
throw new Error('Source database does not exist');
}

// Create backup using stream to handle large files
// Backup using stream
await new Promise((resolve, reject) => {
const readStream = fs.createReadStream(dbPath);
const writeStream = fs.createWriteStream(backupPath);
Expand All @@ -78,7 +78,6 @@ async function createBackup() {
readStream.pipe(writeStream);
});

// Verify backup file exists and has content
const backupStats = fs.statSync(backupPath);
if (backupStats.size === 0) {
throw new Error('Backup file was created but is empty');
Expand Down
152 changes: 85 additions & 67 deletions server/src/repositories/snippetRepository.js
Original file line number Diff line number Diff line change
@@ -1,100 +1,118 @@
const { getDb } = require('../config/database');

class SnippetRepository {
// Helper method to format SELECT statements with proper UTC handling
#getSelectQuery(additional = '') {
return `
SELECT
id,
title,
language,
description,
code,
datetime(updated_at) || 'Z' as updated_at
FROM snippets
${additional}
`.trim();
constructor() {
this.selectAllStmt = null;
this.insertStmt = null;
this.updateStmt = null;
this.deleteStmt = null;
this.selectByIdStmt = null;
}

async findAll() {
#initializeStatements() {
const db = getDb();

if (!this.selectAllStmt) {
this.selectAllStmt = db.prepare(`
SELECT
id,
title,
language,
description,
code,
datetime(updated_at) || 'Z' as updated_at
FROM snippets
ORDER BY updated_at DESC
`);

this.insertStmt = db.prepare(`
INSERT INTO snippets (
title,
language,
description,
code,
updated_at
) VALUES (?, ?, ?, ?, datetime('now', 'utc'))
`);

this.updateStmt = db.prepare(`
UPDATE snippets
SET title = ?,
language = ?,
description = ?,
code = ?,
updated_at = datetime('now', 'utc')
WHERE id = ?
`);

this.deleteStmt = db.prepare('DELETE FROM snippets WHERE id = ?');

this.selectByIdStmt = db.prepare(`
SELECT
id,
title,
language,
description,
code,
datetime(updated_at) || 'Z' as updated_at
FROM snippets
WHERE id = ?
`);
}
}

findAll() {
this.#initializeStatements();
try {
const snippets = await db.all(
this.#getSelectQuery('ORDER BY updated_at DESC')
);
return snippets;
return this.selectAllStmt.all();
} catch (error) {
console.error('Error in findAll:', error);
throw error;
}
}

async create({ title, language, description, code }) {
const db = getDb();
create({ title, language, description, code }) {
this.#initializeStatements();
try {
const result = await db.run(
`INSERT INTO snippets (
title,
language,
description,
code,
updated_at
) VALUES (?, ?, ?, ?, datetime('now', 'utc'))`,
[title, language, description, code]
);
const db = getDb();
const result = db.transaction(() => {
const insertResult = this.insertStmt.run(title, language, description, code);
return this.selectByIdStmt.get(insertResult.lastInsertRowid);
})();

// Fetch the created snippet with UTC formatting
const created = await db.get(
this.#getSelectQuery('WHERE id = ?'),
[result.lastID]
);
return created;
return result;
} catch (error) {
console.error('Error in create:', error);
console.error('Parameters:', { title, language, description, code });
throw error;
}
}

async delete(id) {
const db = getDb();
delete(id) {
this.#initializeStatements();
try {
// Only fetch necessary fields for deletion confirmation
const snippet = await db.get(
this.#getSelectQuery('WHERE id = ?'),
[id]
);

if (snippet) {
await db.run('DELETE FROM snippets WHERE id = ?', [id]);
}

return snippet;
const db = getDb();
return db.transaction(() => {
const snippet = this.selectByIdStmt.get(id);
if (snippet) {
this.deleteStmt.run(id);
}
return snippet;
})();
} catch (error) {
console.error('Error in delete:', error);
throw error;
}
}

async update(id, { title, language, description, code }) {
const db = getDb();
update(id, { title, language, description, code }) {
this.#initializeStatements();
try {
await db.run(
`UPDATE snippets
SET title = ?,
language = ?,
description = ?,
code = ?,
updated_at = datetime('now', 'utc')
WHERE id = ?`,
[title, language, description, code, id]
);

// Return updated snippet with UTC formatting
return db.get(
this.#getSelectQuery('WHERE id = ?'),
[id]
);
const db = getDb();
return db.transaction(() => {
this.updateStmt.run(title, language, description, code, id);
return this.selectByIdStmt.get(id);
})();
} catch (error) {
console.error('Error in update:', error);
throw error;
Expand Down

0 comments on commit 5e3e764

Please sign in to comment.