Skip to content

Commit 40011cc

Browse files
committed
Continue refactor logic placement
1 parent 1f22cf3 commit 40011cc

File tree

11 files changed

+212
-236
lines changed

11 files changed

+212
-236
lines changed

README.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,36 +224,33 @@ You can request a `database_dump.sql` file that exports your database schema and
224224
<pre>
225225
<code>
226226
curl --location 'https://starbasedb.YOUR-ID-HERE.workers.dev/export/dump' \
227-
--header 'Authorization: Bearer ABC123'
227+
--header 'Authorization: Bearer ABC123' \
228228
--output database_dump.sql
229229
</code>
230230
</pre>
231231

232232
<h3>JSON Data Export</h3>
233233
<pre>
234234
<code>
235-
curl
236-
--location 'https://starbasedb.YOUR-ID-HERE.workers.dev/export/json/users' \
237-
--header 'Authorization: Bearer ABC123'
235+
curl --location 'https://starbasedb.YOUR-ID-HERE.workers.dev/export/json/users' \
236+
--header 'Authorization: Bearer ABC123' \
238237
--output output.json
239238
</code>
240239
</pre>
241240

242241
<h3>CSV Data Export</h3>
243242
<pre>
244243
<code>
245-
curl
246-
--location 'https://starbasedb.YOUR-ID-HERE.workers.dev/export/csv/users' \
247-
--header 'Authorization: Bearer ABC123'
244+
curl --location 'https://starbasedb.YOUR-ID-HERE.workers.dev/export/csv/users' \
245+
--header 'Authorization: Bearer ABC123' \
248246
--output output.csv
249247
</code>
250248
</pre>
251249

252250
<h3>SQL Import</h3>
253251
<pre>
254252
<code>
255-
curl
256-
--location 'https://starbasedb.YOUR-ID-HERE.workers.dev/import/dump' \
253+
curl --location 'https://starbasedb.YOUR-ID-HERE.workers.dev/import/dump' \
257254
--header 'Authorization: Bearer ABC123' \
258255
--form 'sqlFile=@"./Desktop/sqldump.sql"'
259256
</code>

src/do.ts

Lines changed: 98 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { DurableObject } from "cloudflare:workers";
22
import { OperationQueueItem, QueryResponse } from "./operation";
3+
import { createResponse } from "./utils";
34

45
export class DatabaseDurableObject extends DurableObject {
56
// Durable storage for the SQL database
@@ -35,27 +36,25 @@ export class DatabaseDurableObject extends DurableObject {
3536
* @param params - Optional parameters for the SQL query.
3637
* @returns A response containing the query result or an error message.
3738
*/
38-
// async executeExternalQuery(sql: string, params: any[] | undefined): Promise<any> {
39-
// try {
40-
// const queries = [{ sql, params }];
41-
// const response = await enqueueOperation(
42-
// queries,
43-
// false,
44-
// false,
45-
// this.operationQueue,
46-
// () => processNextOperation(this.sql, this.operationQueue, this.ctx, this.processingOperation)
47-
// );
48-
49-
// return response;
50-
// } catch (error: any) {
51-
// console.error('Execute External Query Error:', error);
52-
// return null;
53-
// }
54-
// }
39+
async executeExternalQuery(sql: string, params: any[] | undefined): Promise<any> {
40+
try {
41+
const queries = [{ sql, params }];
42+
const response = await this.enqueueOperation(
43+
queries,
44+
false,
45+
false,
46+
this.operationQueue,
47+
() => this.processNextOperation(this.sql, this.operationQueue, this.ctx, this.processingOperation)
48+
);
49+
50+
return response;
51+
} catch (error: any) {
52+
console.error('Execute External Query Error:', error);
53+
return null;
54+
}
55+
}
5556

5657
public executeQuery(sql: string, params: any[] | undefined, isRaw: boolean): QueryResponse {
57-
console.log('Executing INTERNAL query: ', sql, params, isRaw);
58-
5958
try {
6059
let cursor;
6160

@@ -106,84 +105,84 @@ export class DatabaseDurableObject extends DurableObject {
106105
});
107106
}
108107

109-
// enqueueOperation(
110-
// queries: { sql: string; params?: any[] }[],
111-
// isTransaction: boolean,
112-
// isRaw: boolean,
113-
// operationQueue: any[],
114-
// processNextOperation: () => Promise<void>
115-
// ): Promise<{ result?: any, error?: string | undefined, status: number }> {
116-
// const MAX_WAIT_TIME = 25000;
117-
// return new Promise((resolve, reject) => {
118-
// const timeout = setTimeout(() => {
119-
// reject(createResponse(undefined, 'Operation timed out.', 503));
120-
// }, MAX_WAIT_TIME);
121-
122-
// operationQueue.push({
123-
// queries,
124-
// isTransaction,
125-
// isRaw,
126-
// resolve: (value: any) => {
127-
// clearTimeout(timeout);
128-
129-
// resolve({
130-
// result: value,
131-
// error: undefined,
132-
// status: 200
133-
// })
134-
// },
135-
// reject: (reason?: any) => {
136-
// clearTimeout(timeout);
137-
138-
// reject({
139-
// result: undefined,
140-
// error: reason ?? 'Operation failed.',
141-
// status: 500
142-
// })
143-
// }
144-
// });
145-
146-
// processNextOperation().catch((err) => {
147-
// console.error('Error processing operation queue:', err);
148-
// });
149-
// });
150-
// }
151-
152-
// async processNextOperation(
153-
// sqlInstance: any,
154-
// operationQueue: OperationQueueItem[],
155-
// ctx: any,
156-
// processingOperation: { value: boolean }
157-
// ) {
158-
// if (processingOperation.value) {
159-
// // Already processing an operation
160-
// return;
161-
// }
162-
163-
// if (operationQueue.length === 0) {
164-
// // No operations remaining to process
165-
// return;
166-
// }
167-
168-
// processingOperation.value = true;
169-
// const { queries, isTransaction, isRaw, resolve, reject } = operationQueue.shift()!;
170-
171-
// try {
172-
// let result;
173-
174-
// if (isTransaction) {
175-
// result = await this.executeTransaction(queries, isRaw, sqlInstance, ctx);
176-
// } else {
177-
// const { sql, params } = queries[0];
178-
// result = this.executeQuery(sql, params, isRaw);
179-
// }
180-
181-
// resolve(result);
182-
// } catch (error: any) {
183-
// reject(error.message || 'Operation failed.');
184-
// } finally {
185-
// processingOperation.value = false;
186-
// await this.processNextOperation(sqlInstance, operationQueue, ctx, processingOperation);
187-
// }
188-
// }
108+
enqueueOperation(
109+
queries: { sql: string; params?: any[] }[],
110+
isTransaction: boolean,
111+
isRaw: boolean,
112+
operationQueue: any[],
113+
processNextOperation: () => Promise<void>
114+
): Promise<{ result?: any, error?: string | undefined, status: number }> {
115+
const MAX_WAIT_TIME = 25000;
116+
return new Promise((resolve, reject) => {
117+
const timeout = setTimeout(() => {
118+
reject(createResponse(undefined, 'Operation timed out.', 503));
119+
}, MAX_WAIT_TIME);
120+
121+
operationQueue.push({
122+
queries,
123+
isTransaction,
124+
isRaw,
125+
resolve: (value: any) => {
126+
clearTimeout(timeout);
127+
128+
resolve({
129+
result: value,
130+
error: undefined,
131+
status: 200
132+
})
133+
},
134+
reject: (reason?: any) => {
135+
clearTimeout(timeout);
136+
137+
reject({
138+
result: undefined,
139+
error: reason ?? 'Operation failed.',
140+
status: 500
141+
})
142+
}
143+
});
144+
145+
processNextOperation().catch((err) => {
146+
console.error('Error processing operation queue:', err);
147+
});
148+
});
149+
}
150+
151+
async processNextOperation(
152+
sqlInstance: any,
153+
operationQueue: OperationQueueItem[],
154+
ctx: any,
155+
processingOperation: { value: boolean }
156+
) {
157+
if (processingOperation.value) {
158+
// Already processing an operation
159+
return;
160+
}
161+
162+
if (operationQueue.length === 0) {
163+
// No operations remaining to process
164+
return;
165+
}
166+
167+
processingOperation.value = true;
168+
const { queries, isTransaction, isRaw, resolve, reject } = operationQueue.shift()!;
169+
170+
try {
171+
let result;
172+
173+
if (isTransaction) {
174+
result = await this.executeTransaction(queries, isRaw);
175+
} else {
176+
const { sql, params } = queries[0];
177+
result = this.executeQuery(sql, params, isRaw);
178+
}
179+
180+
resolve(result);
181+
} catch (error: any) {
182+
reject(error.message || 'Operation failed.');
183+
} finally {
184+
processingOperation.value = false;
185+
await this.processNextOperation(sqlInstance, operationQueue, ctx, processingOperation);
186+
}
187+
}
189188
}

src/export/csv.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import { getTableData, createExportResponse } from './index';
22
import { createResponse } from '../utils';
3+
import { DataSource } from '..';
34

45
export async function exportTableToCsvRoute(
5-
sql: any,
6-
operationQueue: any,
7-
ctx: any,
8-
processingOperation: { value: boolean },
9-
tableName: string
6+
tableName: string,
7+
dataSource: DataSource
108
): Promise<Response> {
119
try {
12-
const data = await getTableData(sql, operationQueue, ctx, processingOperation, tableName);
10+
const data = await getTableData(tableName, dataSource);
1311

1412
if (data === null) {
1513
return createResponse(undefined, `Table '${tableName}' does not exist.`, 404);

src/export/dump.ts

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,31 @@
1-
import { enqueueOperation, processNextOperation } from '../operation';
1+
import { executeOperation } from '.';
2+
import { DataSource } from '..';
23
import { createResponse } from '../utils';
34

45
export async function dumpDatabaseRoute(
5-
sql: any,
6-
operationQueue: any,
7-
ctx: any,
8-
processingOperation: { value: boolean }
6+
dataSource: DataSource
97
): Promise<Response> {
108
try {
119
// Get all table names
12-
const tablesResult = await enqueueOperation(
13-
[{ sql: "SELECT name FROM sqlite_master WHERE type='table';" }],
14-
false,
15-
false,
16-
operationQueue,
17-
() => processNextOperation(sql, operationQueue, ctx, processingOperation)
18-
);
10+
const tablesResult = await executeOperation([{ sql: "SELECT name FROM sqlite_master WHERE type='table';" }], dataSource)
1911

20-
const tables = tablesResult.result.map((row: any) => row.name);
12+
const tables = tablesResult.map((row: any) => row.name);
2113
let dumpContent = "SQLite format 3\0"; // SQLite file header
2214

2315
// Iterate through all tables
2416
for (const table of tables) {
2517
// Get table schema
26-
const schemaResult = await enqueueOperation(
27-
[{ sql: `SELECT sql FROM sqlite_master WHERE type='table' AND name='${table}';` }],
28-
false,
29-
false,
30-
operationQueue,
31-
() => processNextOperation(sql, operationQueue, ctx, processingOperation)
32-
);
18+
const schemaResult = await executeOperation([{ sql: `SELECT sql FROM sqlite_master WHERE type='table' AND name='${table}';` }], dataSource)
3319

34-
if (schemaResult.result.length) {
35-
const schema = schemaResult.result[0].sql;
20+
if (schemaResult.length) {
21+
const schema = schemaResult[0].sql;
3622
dumpContent += `\n-- Table: ${table}\n${schema};\n\n`;
3723
}
3824

3925
// Get table data
40-
const dataResult = await enqueueOperation(
41-
[{ sql: `SELECT * FROM ${table};` }],
42-
false,
43-
false,
44-
operationQueue,
45-
() => processNextOperation(sql, operationQueue, ctx, processingOperation)
46-
);
26+
const dataResult = await executeOperation([{ sql: `SELECT * FROM ${table};` }], dataSource)
4727

48-
for (const row of dataResult.result) {
28+
for (const row of dataResult) {
4929
const values = Object.values(row).map(value =>
5030
typeof value === 'string' ? `'${value.replace(/'/g, "''")}'` : value
5131
);

src/export/index.ts

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,28 @@
1-
import { enqueueOperation, processNextOperation } from '../operation';
1+
// import { enqueueOperation, processNextOperation } from '../operation';
2+
3+
import { DataSource } from "..";
4+
import { executeTransaction } from "../operation";
5+
6+
export async function executeOperation(queries: { sql: string, params?: any[] }[], dataSource: DataSource): Promise<any> {
7+
const results: any[] = (await executeTransaction(queries, false, dataSource)) as any[];
8+
return results?.length > 0 ? results[0] : undefined;
9+
}
210

311
export async function getTableData(
4-
sql: any,
5-
operationQueue: any,
6-
ctx: any,
7-
processingOperation: { value: boolean },
8-
tableName: string
12+
tableName: string,
13+
dataSource: DataSource
914
): Promise<any[] | null> {
1015
try {
1116
// Verify if the table exists
12-
const tableExistsResult = await enqueueOperation(
13-
[{ sql: `SELECT name FROM sqlite_master WHERE type='table' AND name=?;`, params: [tableName] }],
14-
false,
15-
false,
16-
operationQueue,
17-
() => processNextOperation(sql, operationQueue, ctx, processingOperation)
18-
);
19-
20-
if (tableExistsResult.result.length === 0) {
17+
const tableExistsResult = await executeOperation([{ sql: `SELECT name FROM sqlite_master WHERE type='table' AND name=?;`, params: [tableName] }], dataSource)
18+
19+
if (tableExistsResult.length === 0) {
2120
return null;
2221
}
2322

2423
// Get table data
25-
const dataResult = await enqueueOperation(
26-
[{ sql: `SELECT * FROM ${tableName};` }],
27-
false,
28-
false,
29-
operationQueue,
30-
() => processNextOperation(sql, operationQueue, ctx, processingOperation)
31-
);
32-
33-
return dataResult.result;
24+
const dataResult = await executeOperation([{ sql: `SELECT * FROM ${tableName};` }], dataSource)
25+
return dataResult;
3426
} catch (error: any) {
3527
console.error('Table Data Fetch Error:', error);
3628
throw error;

0 commit comments

Comments
 (0)