Skip to content
Merged
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
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: latest
node-version: 22.13.1
- name: Setup Dependencies
run: |
corepack enable
Expand Down Expand Up @@ -51,11 +51,11 @@ jobs:
#setup node, bun and deno
- uses: actions/setup-node@v4
with:
node-version: latest
node-version: 22.13.1
- uses: oven-sh/setup-bun@v2
- uses: denoland/setup-deno@v2
with:
deno-version: vx.x.x
deno-version: v2.x

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

- name: deno with-javascript-vite
if: matrix.os != 'windows-latest' #https://github.com/denoland/deno/issues/23524#issuecomment-2292075726
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
working-directory: examples/with-javascript-vite
run: deno add npm:@playwright/test && deno run --allow-all npm:playwright test
env:
Expand Down
Binary file modified bun.lockb
Binary file not shown.
15 changes: 11 additions & 4 deletions package-lock.json

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

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sqlitecloud/drivers",
"version": "1.0.354",
"version": "1.0.400",
"description": "SQLiteCloud drivers for Typescript/Javascript in edge, web and node clients",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
Expand Down Expand Up @@ -42,14 +42,16 @@
},
"homepage": "https://github.com/sqlitecloud/sqlitecloud-js#readme",
"dependencies": {
"@craftzdog/react-native-buffer": "^6.0.5",
"buffer": "^6.0.3",
"eventemitter3": "^5.0.1",
"lz4js": "^0.2.0",
"react-native-url-polyfill": "^2.0.0",
"socket.io-client": "^4.8.1",
"whatwg-url": "^14.1.0"
},
"optionalDependencies": {
"@craftzdog/react-native-buffer": "^6.0.5",
"react-native-url-polyfill": "^2.0.0"
},
"peerDependencies": {
"react-native-quick-base64": "*",
"react-native-tcp-socket": "^6.2.0"
Expand Down
7 changes: 4 additions & 3 deletions src/drivers/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ export function formatCommand(command: SQLiteCloudCommand): string {
return serializeData(command.query, false)
}

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

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

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

function serializeData(data: any, zeroString: boolean = false): string {
function serializeData(data: SQLiteCloudDataTypes, zeroString: boolean = false): string {
if (typeof data === 'string') {
let cmd = CMD_STRING
if (zeroString) {
Expand Down
4 changes: 2 additions & 2 deletions test/1brc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ async function createDatabaseAsync(numberOfRows: number): Promise<{ connection:
const createSql = `UNUSE DATABASE; CREATE DATABASE ${database}; USE DATABASE ${database};`
const createResults = await sendCommandsAsync(connection, createSql)
expect(createResults).toBe('OK')
return { database, connection }
return { connection, database }
}

async function destroyDatabaseAsync(connection: SQLiteCloudConnection, database: string) {
Expand Down Expand Up @@ -207,7 +207,7 @@ async function testChallenge(numberOfRows: number, insertChunks = BRC_INSERT_CHU
throw error
}
} finally {
// await destroyDatabaseAsync(connection, database)
await destroyDatabaseAsync(connection, database)
connection?.close()
}
}
125 changes: 78 additions & 47 deletions test/database.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,10 @@
* database.test.ts - test driver api
*/

import { SQLiteCloudRowset, SQLiteCloudRow, SQLiteCloudError, sanitizeSQLiteIdentifier } from '../src/index'
import {
getTestingDatabase,
getTestingDatabaseAsync,
getChinookDatabase,
removeDatabase,
removeDatabaseAsync,
LONG_TIMEOUT,
getChinookWebsocketConnection
} from './shared'
import { describe, expect, it } from '@jest/globals'
import { RowCountCallback } from '../src/drivers/types'
import { expect, describe, it } from '@jest/globals'
import { Database } from 'sqlite3'
import { SQLiteCloudError, SQLiteCloudRow, SQLiteCloudRowset, sanitizeSQLiteIdentifier } from '../src/index'
import { LONG_TIMEOUT, getChinookDatabase, getTestingDatabase, getTestingDatabaseAsync, removeDatabase, removeDatabaseAsync } from './shared'

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

done()
removeDatabase(database, error => {
expect(error).toBeNull()
done()
Expand Down Expand Up @@ -103,7 +93,6 @@ describe('Database.run', () => {
expect(context.totalChanges).toBe(22)
expect(context.finalized).toBe(1)

done()
removeDatabase(database, error => {
expect(error).toBeNull()
done()
Expand Down Expand Up @@ -317,7 +306,7 @@ describe('Database.sql (async)', () => {
const results = await database.sql('SELECT * FROM people WHERE name = ?', 'Emma Johnson')
expect(results).toHaveLength(1)
} finally {
database?.close()
await removeDatabaseAsync(database)
}
})

Expand All @@ -337,7 +326,7 @@ describe('Database.sql (async)', () => {
hobby: 'Collecting clouds'
})
} finally {
database?.close()
await removeDatabaseAsync(database)
}
})

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

describe('should sanitize identifiers', () => {
it('should sanitize database name and run the query', async () => {
const database = await getTestingDatabaseAsync()
let database
try {
database = await getTestingDatabaseAsync()

const databaseName = sanitizeSQLiteIdentifier(database.getConfiguration().database || '')
await expect(database.sql(`USE DATABASE ${databaseName}`)).resolves.toBe('OK')
const databaseName = sanitizeSQLiteIdentifier(database.getConfiguration().database || '')
await expect(database.sql(`USE DATABASE ${databaseName}`)).resolves.toBe('OK')
} finally {
await removeDatabaseAsync(database)
}
})

it('should sanitize table name and run the query', async () => {
const database = await getTestingDatabaseAsync()
let database
try {
database = await getTestingDatabaseAsync()

const table = sanitizeSQLiteIdentifier('people')
await expect(database.sql(`SELECT id FROM ${table} LIMIT 1`)).resolves.toMatchObject([{ id: 1 }])
const table = sanitizeSQLiteIdentifier('people')
await expect(database.sql(`SELECT id FROM ${table} LIMIT 1`)).resolves.toMatchObject([{ id: 1 }])
} finally {
await removeDatabaseAsync(database)
}
})

it('should sanitize SQL Injection as table name', async () => {
const database = await getTestingDatabaseAsync()
const databaseName = database.getConfiguration().database
let database
try {
database = await getTestingDatabaseAsync()
const databaseName = database.getConfiguration().database

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

const table = sanitizeSQLiteIdentifier('people; -- ')
await expect(database.sql(`SELECT * FROM ${table} WHERE people = 1`)).rejects.toThrow('no such table: people; --')
const table = sanitizeSQLiteIdentifier('people; -- ')
await expect(database.sql(`SELECT * FROM ${table} WHERE people = 1`)).rejects.toThrow('no such table: people; --')
} finally {
await removeDatabaseAsync(database)
}
})
})

it('should throw exception when using table name as binding', async () => {
const database = await getTestingDatabaseAsync()
const table = 'people'
await expect(database.sql`SELECT * FROM ${table}`).rejects.toThrow('near "?": syntax error')
let database
try {
database = await getTestingDatabaseAsync()
const table = 'people'
await expect(database.sql`SELECT * FROM ${table}`).rejects.toThrow('near "?": syntax error')
} finally {
await removeDatabaseAsync(database)
}
})

it('should built in commands accept bindings', async () => {
const database = await getTestingDatabaseAsync()
it('should commands accept bindings', async () => {
let database
try {
database = await getTestingDatabaseAsync()

const databaseName = database.getConfiguration().database || ''
await expect(database.sql`USE DATABASE ${databaseName}`).resolves.toBe('OK')

const databaseNameInjectSQL = `${databaseName}; SELECT * FROM people`
await expect(database.sql`USE DATABASE ${databaseNameInjectSQL}`).rejects.toThrow(`Database name contains invalid characters (${databaseNameInjectSQL}).`)

let key = 'logo_level'
let value = 'debug'
await expect(database.sql`SET KEY ${key} TO ${value}`).resolves.toBe('OK')

const databaseName = database.getConfiguration().database || ''
await expect(database.sql`USE DATABASE ${databaseName}`).resolves.toBe('OK')
key = 'logo_level'
value = 'debug; DROP TABLE people'
await expect(database.sql`SET KEY ${key} TO ${value}`).resolves.toBe('OK')
const result = await database.sql`SELECT * FROM people`
expect(result.length).toBeGreaterThan(0)
} finally {
await removeDatabaseAsync(database)
}
})

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

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

key = 'logo_level'
value = 'debug; DROP TABLE people'
await expect(database.sql`SET KEY ${key} TO ${value}`).resolves.toBe('OK')
const result = await database.sql`SELECT * FROM people`
expect(result.length).toBeGreaterThan(0)
results = await database.sql('SELECT * FROM people WHERE name = ?;', name)
expect(results).toHaveLength(1)
expect(results[0].name).toEqual(name)
} finally {
await removeDatabaseAsync(database)
}
})
})
4 changes: 2 additions & 2 deletions test/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ export const WARN_SPEED_MS = 500
export const EXPECT_SPEED_MS = 6 * 1000

/** Number of times or size of stress (when repeated in sequence) */
export const SEQUENCE_TEST_SIZE = 150
export const SEQUENCE_TEST_SIZE = 90
/** Concurrency size for multiple connection tests */
export const SIMULTANEOUS_TEST_SIZE = 150
export const SIMULTANEOUS_TEST_SIZE = 90

/** Testing database from .env file */
export const CHINOOK_DATABASE_URL = process.env.CHINOOK_DATABASE_URL as string
Expand Down
2 changes: 1 addition & 1 deletion test/stress.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
EXPECT_SPEED_MS
} from './shared'

describe('stress testing', () => {
describe.skip('stress testing', () => {
it(
'should do lots of read connections in sequence',
async () => {
Expand Down
Loading