Skip to content

Commit fb677a0

Browse files
danielebriggiGioee
andauthored
fix(unicode): count bytes not characters (#195)
* fix(unicode): count bytes not characters * fix(tests): skip stress tests * fix database test * node lts instead of latest * node version to lts 22 * setup deno lts fix * call deno-vite test inside test folder * skip macos deno vite * back to root folder test deno * deno install browsers * skip deno with-javascript-vite test * react native optional dependencies --------- Co-authored-by: Daniele Briggi <=> Co-authored-by: Gioele Cantoni <[email protected]>
1 parent 490844e commit fb677a0

File tree

9 files changed

+107
-66
lines changed

9 files changed

+107
-66
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
- uses: actions/checkout@v4
1616
- uses: actions/setup-node@v4
1717
with:
18-
node-version: latest
18+
node-version: 22.13.1
1919
- name: Setup Dependencies
2020
run: |
2121
corepack enable
@@ -51,11 +51,11 @@ jobs:
5151
#setup node, bun and deno
5252
- uses: actions/setup-node@v4
5353
with:
54-
node-version: latest
54+
node-version: 22.13.1
5555
- uses: oven-sh/setup-bun@v2
5656
- uses: denoland/setup-deno@v2
5757
with:
58-
deno-version: vx.x.x
58+
deno-version: v2.x
5959

6060
- name: setup playwright for browser related test
6161
run: npx playwright install --with-deps && npx playwright install msedge && npx playwright install chrome
@@ -282,7 +282,7 @@ jobs:
282282
VITE_DATABASE_URL: ${{ secrets.CHINOOK_DATABASE_URL }}
283283

284284
- name: deno with-javascript-vite
285-
if: matrix.os != 'windows-latest' #https://github.com/denoland/deno/issues/23524#issuecomment-2292075726
285+
if: false #matrix.os != 'windows-latest' windows: https://github.com/denoland/deno/issues/23524#issuecomment-2292075726 linux-ubuntu: https://github.com/sqlitecloud/sqlitecloud-js/issues/197
286286
working-directory: examples/with-javascript-vite
287287
run: deno add npm:@playwright/test && deno run --allow-all npm:playwright test
288288
env:

bun.lockb

-354 Bytes
Binary file not shown.

package-lock.json

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sqlitecloud/drivers",
3-
"version": "1.0.354",
3+
"version": "1.0.400",
44
"description": "SQLiteCloud drivers for Typescript/Javascript in edge, web and node clients",
55
"main": "./lib/index.js",
66
"types": "./lib/index.d.ts",
@@ -42,14 +42,16 @@
4242
},
4343
"homepage": "https://github.com/sqlitecloud/sqlitecloud-js#readme",
4444
"dependencies": {
45-
"@craftzdog/react-native-buffer": "^6.0.5",
4645
"buffer": "^6.0.3",
4746
"eventemitter3": "^5.0.1",
4847
"lz4js": "^0.2.0",
49-
"react-native-url-polyfill": "^2.0.0",
5048
"socket.io-client": "^4.8.1",
5149
"whatwg-url": "^14.1.0"
5250
},
51+
"optionalDependencies": {
52+
"@craftzdog/react-native-buffer": "^6.0.5",
53+
"react-native-url-polyfill": "^2.0.0"
54+
},
5355
"peerDependencies": {
5456
"react-native-quick-base64": "*",
5557
"react-native-tcp-socket": "^6.2.0"

src/drivers/protocol.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ export function formatCommand(command: SQLiteCloudCommand): string {
346346
return serializeData(command.query, false)
347347
}
348348

349-
function serializeCommand(data: any[], zeroString: boolean = false): string {
349+
function serializeCommand(data: SQLiteCloudDataTypes[], zeroString: boolean = false): string {
350350
const n = data.length
351351
let serializedData = `${n} `
352352

@@ -356,11 +356,12 @@ function serializeCommand(data: any[], zeroString: boolean = false): string {
356356
serializedData += serializeData(data[i], zs)
357357
}
358358

359-
const header = `${CMD_ARRAY}${serializedData.length} `
359+
const bytesTotal = Buffer.byteLength(serializedData, 'utf-8')
360+
const header = `${CMD_ARRAY}${bytesTotal} `
360361
return header + serializedData
361362
}
362363

363-
function serializeData(data: any, zeroString: boolean = false): string {
364+
function serializeData(data: SQLiteCloudDataTypes, zeroString: boolean = false): string {
364365
if (typeof data === 'string') {
365366
let cmd = CMD_STRING
366367
if (zeroString) {

test/1brc.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ async function createDatabaseAsync(numberOfRows: number): Promise<{ connection:
7878
const createSql = `UNUSE DATABASE; CREATE DATABASE ${database}; USE DATABASE ${database};`
7979
const createResults = await sendCommandsAsync(connection, createSql)
8080
expect(createResults).toBe('OK')
81-
return { database, connection }
81+
return { connection, database }
8282
}
8383

8484
async function destroyDatabaseAsync(connection: SQLiteCloudConnection, database: string) {
@@ -207,7 +207,7 @@ async function testChallenge(numberOfRows: number, insertChunks = BRC_INSERT_CHU
207207
throw error
208208
}
209209
} finally {
210-
// await destroyDatabaseAsync(connection, database)
210+
await destroyDatabaseAsync(connection, database)
211211
connection?.close()
212212
}
213213
}

test/database.test.ts

Lines changed: 78 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,10 @@
22
* database.test.ts - test driver api
33
*/
44

5-
import { SQLiteCloudRowset, SQLiteCloudRow, SQLiteCloudError, sanitizeSQLiteIdentifier } from '../src/index'
6-
import {
7-
getTestingDatabase,
8-
getTestingDatabaseAsync,
9-
getChinookDatabase,
10-
removeDatabase,
11-
removeDatabaseAsync,
12-
LONG_TIMEOUT,
13-
getChinookWebsocketConnection
14-
} from './shared'
5+
import { describe, expect, it } from '@jest/globals'
156
import { RowCountCallback } from '../src/drivers/types'
16-
import { expect, describe, it } from '@jest/globals'
17-
import { Database } from 'sqlite3'
7+
import { SQLiteCloudError, SQLiteCloudRow, SQLiteCloudRowset, sanitizeSQLiteIdentifier } from '../src/index'
8+
import { LONG_TIMEOUT, getChinookDatabase, getTestingDatabase, getTestingDatabaseAsync, removeDatabase, removeDatabaseAsync } from './shared'
189

1910
//
2011
// utility methods to setup and destroy temporary test databases
@@ -44,7 +35,6 @@ describe('Database.run', () => {
4435
expect(context.totalChanges).toBe(22)
4536
expect(context.finalized).toBe(1)
4637

47-
done()
4838
removeDatabase(database, error => {
4939
expect(error).toBeNull()
5040
done()
@@ -103,7 +93,6 @@ describe('Database.run', () => {
10393
expect(context.totalChanges).toBe(22)
10494
expect(context.finalized).toBe(1)
10595

106-
done()
10796
removeDatabase(database, error => {
10897
expect(error).toBeNull()
10998
done()
@@ -317,7 +306,7 @@ describe('Database.sql (async)', () => {
317306
const results = await database.sql('SELECT * FROM people WHERE name = ?', 'Emma Johnson')
318307
expect(results).toHaveLength(1)
319308
} finally {
320-
database?.close()
309+
await removeDatabaseAsync(database)
321310
}
322311
})
323312

@@ -337,7 +326,7 @@ describe('Database.sql (async)', () => {
337326
hobby: 'Collecting clouds'
338327
})
339328
} finally {
340-
database?.close()
329+
await removeDatabaseAsync(database)
341330
}
342331
})
343332

@@ -487,56 +476,98 @@ describe('Database.sql (async)', () => {
487476

488477
describe('should sanitize identifiers', () => {
489478
it('should sanitize database name and run the query', async () => {
490-
const database = await getTestingDatabaseAsync()
479+
let database
480+
try {
481+
database = await getTestingDatabaseAsync()
491482

492-
const databaseName = sanitizeSQLiteIdentifier(database.getConfiguration().database || '')
493-
await expect(database.sql(`USE DATABASE ${databaseName}`)).resolves.toBe('OK')
483+
const databaseName = sanitizeSQLiteIdentifier(database.getConfiguration().database || '')
484+
await expect(database.sql(`USE DATABASE ${databaseName}`)).resolves.toBe('OK')
485+
} finally {
486+
await removeDatabaseAsync(database)
487+
}
494488
})
495489

496490
it('should sanitize table name and run the query', async () => {
497-
const database = await getTestingDatabaseAsync()
491+
let database
492+
try {
493+
database = await getTestingDatabaseAsync()
498494

499-
const table = sanitizeSQLiteIdentifier('people')
500-
await expect(database.sql(`SELECT id FROM ${table} LIMIT 1`)).resolves.toMatchObject([{ id: 1 }])
495+
const table = sanitizeSQLiteIdentifier('people')
496+
await expect(database.sql(`SELECT id FROM ${table} LIMIT 1`)).resolves.toMatchObject([{ id: 1 }])
497+
} finally {
498+
await removeDatabaseAsync(database)
499+
}
501500
})
502501

503502
it('should sanitize SQL Injection as table name', async () => {
504-
const database = await getTestingDatabaseAsync()
505-
const databaseName = database.getConfiguration().database
503+
let database
504+
try {
505+
database = await getTestingDatabaseAsync()
506+
const databaseName = database.getConfiguration().database
506507

507-
const sanitizedDBName = sanitizeSQLiteIdentifier(`${databaseName}; SELECT * FROM people; -- `)
508-
await expect(database.sql(`USE DATABASE ${sanitizedDBName}`)).rejects.toThrow(
509-
`Database name contains invalid characters (${databaseName}; SELECT * FROM people; --).`
510-
)
508+
const sanitizedDBName = sanitizeSQLiteIdentifier(`${databaseName}; SELECT * FROM people; -- `)
509+
await expect(database.sql(`USE DATABASE ${sanitizedDBName}`)).rejects.toThrow(
510+
`Database name contains invalid characters (${databaseName}; SELECT * FROM people; --).`
511+
)
511512

512-
const table = sanitizeSQLiteIdentifier('people; -- ')
513-
await expect(database.sql(`SELECT * FROM ${table} WHERE people = 1`)).rejects.toThrow('no such table: people; --')
513+
const table = sanitizeSQLiteIdentifier('people; -- ')
514+
await expect(database.sql(`SELECT * FROM ${table} WHERE people = 1`)).rejects.toThrow('no such table: people; --')
515+
} finally {
516+
await removeDatabaseAsync(database)
517+
}
514518
})
515519
})
516520

517521
it('should throw exception when using table name as binding', async () => {
518-
const database = await getTestingDatabaseAsync()
519-
const table = 'people'
520-
await expect(database.sql`SELECT * FROM ${table}`).rejects.toThrow('near "?": syntax error')
522+
let database
523+
try {
524+
database = await getTestingDatabaseAsync()
525+
const table = 'people'
526+
await expect(database.sql`SELECT * FROM ${table}`).rejects.toThrow('near "?": syntax error')
527+
} finally {
528+
await removeDatabaseAsync(database)
529+
}
521530
})
522531

523-
it('should built in commands accept bindings', async () => {
524-
const database = await getTestingDatabaseAsync()
532+
it('should commands accept bindings', async () => {
533+
let database
534+
try {
535+
database = await getTestingDatabaseAsync()
536+
537+
const databaseName = database.getConfiguration().database || ''
538+
await expect(database.sql`USE DATABASE ${databaseName}`).resolves.toBe('OK')
539+
540+
const databaseNameInjectSQL = `${databaseName}; SELECT * FROM people`
541+
await expect(database.sql`USE DATABASE ${databaseNameInjectSQL}`).rejects.toThrow(`Database name contains invalid characters (${databaseNameInjectSQL}).`)
542+
543+
let key = 'logo_level'
544+
let value = 'debug'
545+
await expect(database.sql`SET KEY ${key} TO ${value}`).resolves.toBe('OK')
525546

526-
const databaseName = database.getConfiguration().database || ''
527-
await expect(database.sql`USE DATABASE ${databaseName}`).resolves.toBe('OK')
547+
key = 'logo_level'
548+
value = 'debug; DROP TABLE people'
549+
await expect(database.sql`SET KEY ${key} TO ${value}`).resolves.toBe('OK')
550+
const result = await database.sql`SELECT * FROM people`
551+
expect(result.length).toBeGreaterThan(0)
552+
} finally {
553+
await removeDatabaseAsync(database)
554+
}
555+
})
528556

529-
const databaseNameInjectSQL = `${databaseName}; SELECT * FROM people`
530-
await expect(database.sql`USE DATABASE ${databaseNameInjectSQL}`).rejects.toThrow(`Database name contains invalid characters (${databaseNameInjectSQL}).`)
557+
it('binding should work with unicode character', async () => {
558+
let database
559+
try {
560+
database = await getTestingDatabaseAsync()
561+
const name = 'unicorn-🦄'
531562

532-
let key = 'logo_level'
533-
let value = 'debug'
534-
await expect(database.sql`SET KEY ${key} TO ${value}`).resolves.toBe('OK')
563+
let results = await database.sql('INSERT INTO people (name, age, hobby) VALUES (?, 11, "");', name)
564+
expect(results.changes).toEqual(1)
535565

536-
key = 'logo_level'
537-
value = 'debug; DROP TABLE people'
538-
await expect(database.sql`SET KEY ${key} TO ${value}`).resolves.toBe('OK')
539-
const result = await database.sql`SELECT * FROM people`
540-
expect(result.length).toBeGreaterThan(0)
566+
results = await database.sql('SELECT * FROM people WHERE name = ?;', name)
567+
expect(results).toHaveLength(1)
568+
expect(results[0].name).toEqual(name)
569+
} finally {
570+
await removeDatabaseAsync(database)
571+
}
541572
})
542573
})

test/shared.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ export const WARN_SPEED_MS = 500
2525
export const EXPECT_SPEED_MS = 6 * 1000
2626

2727
/** Number of times or size of stress (when repeated in sequence) */
28-
export const SEQUENCE_TEST_SIZE = 150
28+
export const SEQUENCE_TEST_SIZE = 90
2929
/** Concurrency size for multiple connection tests */
30-
export const SIMULTANEOUS_TEST_SIZE = 150
30+
export const SIMULTANEOUS_TEST_SIZE = 90
3131

3232
/** Testing database from .env file */
3333
export const CHINOOK_DATABASE_URL = process.env.CHINOOK_DATABASE_URL as string

test/stress.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
EXPECT_SPEED_MS
1515
} from './shared'
1616

17-
describe('stress testing', () => {
17+
describe.skip('stress testing', () => {
1818
it(
1919
'should do lots of read connections in sequence',
2020
async () => {

0 commit comments

Comments
 (0)