Skip to content

Commit 291eab8

Browse files
committed
database: decaff postgres-user-query-queue.coffee
1 parent 5bb3770 commit 291eab8

File tree

12 files changed

+3878
-268
lines changed

12 files changed

+3878
-268
lines changed

src/packages/database/DB_DEVELOPMENT.md

Lines changed: 108 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,22 @@
77

88
## Overview
99

10-
This document tracks the migration of all CoffeeScript code in the `@cocalc/database` package to TypeScript. The goal is to eliminate the 7,262 lines of CoffeeScript code across 8 files while maintaining backward compatibility and ensuring comprehensive test coverage.
10+
This document tracks the migration of all CoffeeScript code in the `@cocalc/database` package to TypeScript. The goal is to eliminate the 6,827 lines of CoffeeScript code across 5 files while maintaining backward compatibility and ensuring comprehensive test coverage.
1111

1212
**WARNING**: This is the single scariest chunk of CoffeeScript left in CoCalc!
1313

1414
## Current State
1515

1616
### CoffeeScript Files (by size)
1717

18-
| File | Lines | Description | Priority |
19-
| ---------------------------------- | --------- | ----------------------------------------------- | ------------ |
20-
| `postgres-server-queries.coffee` | 2,518 | Server-side database queries | High |
21-
| `postgres-user-queries.coffee` | 1,790 | User-facing query handling | High |
22-
| `postgres-base.coffee` | 1,156 | Core PostgreSQL class and connection management | **Critical** |
23-
| `postgres-blobs.coffee` | 760 | Blob storage operations | Medium |
24-
| `postgres-synctable.coffee` | 604 | Real-time table synchronization | Medium |
25-
| `postgres-user-query-queue.coffee` | 218 | Queue management for user queries | Low |
26-
| `postgres-ops.coffee` | 168 | Database operations | Low |
27-
| `filesystem-bucket.coffee` | 48 | Filesystem bucket utilities | Low |
28-
| **Total** | **7,262** | | |
18+
| File | Lines | Description | Priority |
19+
| -------------------------------- | --------- | ----------------------------------------------- | ------------ |
20+
| `postgres-server-queries.coffee` | 2,518 | Server-side database queries | High |
21+
| `postgres-user-queries.coffee` | 1,789 | User-facing query handling | High |
22+
| `postgres-base.coffee` | 1,156 | Core PostgreSQL class and connection management | **Critical** |
23+
| `postgres-blobs.coffee` | 760 | Blob storage operations | Medium |
24+
| `postgres-synctable.coffee` | 604 | Real-time table synchronization | Medium |
25+
| **Total** | **6,827** | | |
2926

3027
### Existing TypeScript Structure
3128

@@ -52,21 +49,23 @@ The package currently compiles both TypeScript and CoffeeScript during the build
5249
The `index.ts` file is the main entry point that orchestrates the database package:
5350

5451
```typescript
52+
import { extend_PostgreSQL as extendPostgresOps } from "./postgres-ops";
53+
54+
const base = require("./postgres-base");
55+
5556
export function db(opts = {}): PostgreSQL {
5657
if (theDB === undefined) {
5758
let PostgreSQL = base.PostgreSQL;
5859

59-
for (const module of [
60-
"server-queries",
61-
"blobs",
62-
"synctable",
63-
"user-queries",
64-
"ops",
65-
]) {
66-
PostgreSQL = require(`./postgres-${module}`).extend_PostgreSQL(
67-
PostgreSQL,
68-
);
69-
}
60+
PostgreSQL = require("./postgres-server-queries").extend_PostgreSQL(
61+
PostgreSQL,
62+
);
63+
PostgreSQL = require("./postgres-blobs").extend_PostgreSQL(PostgreSQL);
64+
PostgreSQL = require("./postgres-synctable").extend_PostgreSQL(PostgreSQL);
65+
PostgreSQL = require("./postgres-user-queries").extend_PostgreSQL(
66+
PostgreSQL,
67+
);
68+
PostgreSQL = extendPostgresOps(PostgreSQL);
7069
const theDBnew = new PostgreSQL(opts);
7170
setupRecordConnectErrors(theDBnew);
7271
theDB = theDBnew;
@@ -81,6 +80,7 @@ export function db(opts = {}): PostgreSQL {
8180
2. **Class Extension Pattern**: Each CoffeeScript module exports `extend_PostgreSQL(ext)` that creates a new class extending the previous one
8281
3. **Composition Order Matters**: `server-queries``blobs``synctable``user-queries``ops`
8382
4. **Each module adds methods** to the class through CoffeeScript's class extension syntax
83+
5. **Mixed implementation**: `postgres-ops.ts` is TypeScript, while other `postgres-*.coffee` modules still use CoffeeScript wrappers
8484

8585
### Two Database Access Patterns
8686

@@ -166,7 +166,7 @@ coverageThreshold: {
166166

167167
#### 1.3 Decaffeinate Tool Testing ✅
168168

169-
Tested `decaffeinate` with sample code from `postgres-ops.coffee`:
169+
Tested `decaffeinate` with sample code from the former `postgres-ops.coffee`:
170170

171171
```bash
172172
cat << 'EOF' | npx decaffeinate --use-js-modules
@@ -190,6 +190,38 @@ EOF
190190

191191
**Conclusion**: `decaffeinate` is a good starting point but requires manual cleanup and TypeScript transformation. The output is readable and provides a solid foundation for conversion.
192192

193+
#### 1.4 Recommended Decaffeinate Parameters ✅
194+
195+
Based on the `postgres-user-query-queue` migration, the following parameters produce optimal output:
196+
197+
```bash
198+
npx decaffeinate \
199+
--use-js-modules \
200+
--loose \
201+
--optional-chaining \
202+
--logical-assignment \
203+
<filename>.coffee
204+
```
205+
206+
**Parameter explanations:**
207+
208+
- `--use-js-modules`: Converts `require`/`module.exports` to ES6 `import`/`export` (cleaner, modern)
209+
- `--loose`: Enables all loose transformations for simpler output
210+
- `--optional-chaining`: Uses `?.` operator for safer property access
211+
- `--logical-assignment`: Uses ES2021 `&&=`, `||=`, `??=` operators
212+
213+
**What still needs manual fixing after decaffeinate:**
214+
215+
1. **Import cleanup**: Consolidate messy require patterns into clean ES6 imports
216+
2. **Add TypeScript types**: Add interfaces, type annotations, and proper typing
217+
3. **Remove unnecessary code**: Delete decaffeinate suggestions, unnecessary IIFEs, and redundant returns
218+
4. **Fix method bindings**: Remove constructor binding boilerplate (lines 73-82 in generated output)
219+
5. **Fix `delete` operators**: Add type assertions `(obj as any).prop` for delete operations
220+
6. **Export cleanup**: Change `export { _ClassName as ClassName }` to `export class ClassName`
221+
7. **Metrics imports**: Fix missing default exports (e.g., `import * as metrics` instead of `import metrics`)
222+
223+
**Time savings**: Using decaffeinate reduces migration time by ~50% compared to manual rewriting, while still producing clean, idiomatic TypeScript after manual fixes.
224+
193225
### Phase 2: Incremental Method Migration
194226

195227
#### 2.1 Migration Workflow (Test-Driven Approach)
@@ -352,16 +384,19 @@ export function backupTableCB(opts: {
352384
}
353385
```
354386
355-
**In the CoffeeScript wrapper:**
387+
**In the wrapper module (CoffeeScript or TypeScript):**
356388
357389
```coffeescript
358-
# In postgres-ops.coffee
359-
{ backupTableCB } = require('./postgres/backup')
390+
# In postgres-ops.ts
391+
import { backupTableCB } from "./postgres/ops";
360392
361-
exports.extend_PostgreSQL = (ext) -> class PostgreSQL extends ext
362-
_backup_table: (opts) =>
363-
# IMPORTANT: Use .call(this, opts) to preserve instance context
364-
backupTableCB.call(this, opts)
393+
export function extend_PostgreSQL(ext: PostgreSQLConstructor) {
394+
return class PostgreSQL extends ext {
395+
_backup_table(opts: BackupTableOptions & { cb: CB }): void {
396+
backupTableCB(this, opts);
397+
}
398+
};
399+
}
365400
```
366401
367402
**For methods that need instance properties (this.\_host, this.\_client, etc.):**
@@ -469,20 +504,15 @@ pnpm test postgres/ops/backup.test.ts postgres/ops/restore.test.ts
469504
- Then connection management
470505
- Finally complex query building
471506
472-
2. **postgres-ops.coffee** - Database operations
473-
- Standalone operations first
507+
2. **postgres-user-query-queue.coffee** - Queue management
474508
475-
3. **filesystem-bucket.coffee** - Smallest file, good for validation
509+
3. **postgres-blobs.coffee** - Blob operations (already has `postgres/blobs.ts` partial implementation)
476510
477-
4. **postgres-user-query-queue.coffee** - Queue management
511+
4. **postgres-synctable.coffee** - Real-time synchronization
478512
479-
5. **postgres-blobs.coffee** - Blob operations (already has `postgres/blobs.ts` partial implementation)
513+
5. **postgres-user-queries.coffee** - User query handling
480514
481-
6. **postgres-synctable.coffee** - Real-time synchronization
482-
483-
7. **postgres-user-queries.coffee** - User query handling
484-
485-
8. **postgres-server-queries.coffee** - Largest, most complex
515+
6. **postgres-server-queries.coffee** - Largest, most complex
486516
487517
### Phase 3: Class Consolidation
488518
@@ -527,7 +557,7 @@ export class PostgreSQL extends EventEmitter {
527557
// Methods from postgres-user-queries.coffee
528558
async userQuery(opts) { ... }
529559
530-
// Methods from postgres-ops.coffee
560+
// Methods from postgres-ops (TypeScript)
531561
async backupTables(opts) { ... }
532562
}
533563
```
@@ -594,7 +624,6 @@ export function db(opts = {}): PostgreSQL {
594624
- Remove `coffeescript` from devDependencies
595625
- **Remove `decaffeinate` from devDependencies** (no longer needed)
596626
- Update exports in `package.json` if needed
597-
- Remove `filesystem-bucket.coffee` (migrate to TypeScript first)
598627
599628
**Updated build script:**
600629
@@ -697,16 +726,49 @@ pnpm test --watch
697726
698727
- **postgres-ops**: Migrated to TypeScript, split into `postgres/ops/backup.ts`, `postgres/ops/restore.ts`, and `postgres/ops/utils.ts`; tests split accordingly
699728
- **filesystem-bucket**: Migrated to TypeScript with new tests
729+
- **postgres-user-query-queue**: Migrated to TypeScript as `user-query/queue.ts` with 17 comprehensive tests; all tests pass (17/17 ✅)
700730
701731
### In Progress
702732
703-
_None yet_
733+
#### postgres-user-queries.coffee → user-query/queries.ts
734+
735+
**Status**: ✅ Test suite complete - 150/150 tests passing (100%)
736+
**File size**: 1,791 lines (CoffeeScript) → 2,461 lines (TypeScript)
737+
**Complexity**: Very High - 44+ methods including complex authorization, changefeed, and query logic
738+
**Location**: `packages/database/user-query/queries.ts`
739+
**Test file**: `packages/database/user-query/queries.test.ts`
740+
741+
**Test Suite Summary**:
742+
743+
- **150 comprehensive tests** covering all 44+ methods
744+
- **100% pass rate** validated against CoffeeScript baseline
745+
- **Test execution time**: 0.981 seconds
746+
- **Coverage areas**: Public API (19 tests), Query Routing (28 tests), Authorization (12 tests), Set Queries (26 tests), Get Queries (23 tests), Changefeeds (14 tests), Hooks (20 tests), Syncstring Permissions (8 tests)
747+
748+
**Key Test Patterns Discovered**:
749+
750+
- All methods use `opts.cb` pattern, not separate callback parameter
751+
- PostgreSQL COUNT returns numbers, not strings
752+
- Tracker objects require full EventEmitter interface (on, once, removeListener)
753+
- Methods using `await callback2 @_query` work with synchronous mocks
754+
755+
**Migration Progress**:
756+
757+
- [x] Create comprehensive test suite (150 tests)
758+
- [x] Validate 100% tests passing against CoffeeScript baseline
759+
- [ ] Run decaffeinate to generate TypeScript
760+
- [ ] Clean up generated code and add types
761+
- [ ] Re-route tests to TypeScript implementation
762+
- [ ] Verify all 150 tests still pass
763+
- [ ] Update database/index.ts
764+
- [ ] Build and typecheck
765+
- [ ] Remove old .coffee file
704766
705767
### Next Up
706768
707-
Recommended next target:
769+
After postgres-user-queries:
708770
709-
- **postgres-user-query-queue.coffee** - Small file, good next step before moving to larger query modules
771+
- **postgres-synctable.coffee** - 604 lines, real-time table synchronization
710772
711773
## Decision Log
712774

src/packages/database/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ const base = require("./postgres-base");
1919
const postgresServerQueries = require("./postgres-server-queries");
2020
const postgresBlobs = require("./postgres-blobs");
2121
const postgresSynctable = require("./postgres-synctable");
22-
const postgresUserQueries = require("./postgres-user-queries");
22+
// Migrated to TypeScript: user-query/queries.ts
23+
import { extend_PostgreSQL as extendPostgresUserQueries } from "./user-query/queries";
2324

2425
export const {
2526
pg_type,
@@ -44,7 +45,7 @@ export function db(opts = {}): PostgreSQL {
4445
PostgreSQL = postgresServerQueries.extend_PostgreSQL(PostgreSQL);
4546
PostgreSQL = postgresBlobs.extend_PostgreSQL(PostgreSQL);
4647
PostgreSQL = postgresSynctable.extend_PostgreSQL(PostgreSQL);
47-
PostgreSQL = postgresUserQueries.extend_PostgreSQL(PostgreSQL);
48+
PostgreSQL = extendPostgresUserQueries(PostgreSQL);
4849
PostgreSQL = extendPostgresOps(PostgreSQL);
4950
const theDBnew = new PostgreSQL(opts);
5051
setupRecordConnectErrors(theDBnew);

src/packages/database/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"preinstall": "npx only-allow pnpm",
4646
"build": "../node_modules/.bin/tsc --build && coffee -c -o dist/ ./",
4747
"clean": "rm -rf dist",
48-
"test": "pnpm exec jest --forceExit --runInBand",
48+
"test": "pnpm exec jest --forceExit --runInBand --detectOpenHandles",
4949
"coverage": "pnpm exec jest --coverage --forceExit --runInBand",
5050
"depcheck": "pnpx depcheck | grep -Ev '\\.coffee|coffee$'",
5151
"prepublishOnly": "pnpm test"

src/packages/database/postgres-user-queries.coffee

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ lodash = require('lodash')
2121

2222
{one_result, all_results, count_result, pg_type, quote_field} = require('./postgres-base')
2323

24-
{UserQueryQueue} = require('./postgres-user-query-queue')
24+
# Migrated to TypeScript: user-query/queue.ts
25+
{UserQueryQueue} = require('./user-query/queue')
2526

2627
{defaults} = misc = require('@cocalc/util/misc')
2728
required = defaults.required

0 commit comments

Comments
 (0)