Skip to content

Commit

Permalink
fix: add functions test
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobprall committed Dec 27, 2024
1 parent 32b98f1 commit c6c85b0
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 38 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sqlitecloud/drivers",
"version": "1.0.360",
"version": "1.0.361",
"description": "SQLiteCloud drivers for Typescript/Javascript in edge, web and node clients",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
Expand Down
49 changes: 19 additions & 30 deletions src/packages/_functions/FunctionsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import { Fetch, resolveFetch } from '../utils/fetch'
* @param headers - The headers to pass to the function.
*/
interface FunctionInvokeOptions {
args: any[]
params: Record<string, any>
headers?: Record<string, string>
apiKey?: string
}

/**
Expand All @@ -27,13 +28,15 @@ export class FunctionsClient {
constructor(
connectionString: string,
options: {
customFetch?: Fetch,
fetch?: Fetch,
headers?: Record<string, string>
} = {}
} = {
headers: {}
}
) {
this.url = getAPIUrl(connectionString, FUNCTIONS_ROOT_PATH)
this.fetch = resolveFetch(options.customFetch)
this.headers = options.headers ? { ...DEFAULT_HEADERS, ...options.headers } : { ...DEFAULT_HEADERS }
this.fetch = resolveFetch(options.fetch)
this.headers = { ...DEFAULT_HEADERS, ...options.headers }
}
// TODO: check authorization and api key setup in Gateway
setAuth(token: string) {
Expand All @@ -43,56 +46,42 @@ export class FunctionsClient {
async invoke(functionId: string, options: FunctionInvokeOptions) {
let body;
let _headers: Record<string, string> = {}
if (options.args &&
if (options.params &&
((options.headers && !Object.prototype.hasOwnProperty.call(options.headers, 'Content-Type')) || !options.headers)
) {
if (
(typeof Blob !== 'undefined' && options.args instanceof Blob) ||
options.args instanceof ArrayBuffer
(typeof Blob !== 'undefined' && options.params instanceof Blob) ||
options.params instanceof ArrayBuffer
) {
// will work for File as File inherits Blob
// also works for ArrayBuffer as it is the same underlying structure as a Blob
_headers['Content-Type'] = 'application/octet-stream'
body = options.args
} else if (typeof options.args === 'string') {
body = options.params
} else if (typeof options.params === 'string') {
// plain string
_headers['Content-Type'] = 'text/plain'
body = options.args
} else if (typeof FormData !== 'undefined' && options.args instanceof FormData) {
body = options.params
} else if (typeof FormData !== 'undefined' && options.params instanceof FormData) {
_headers['Content-Type'] = 'multipart/form-data'
body = options.args
body = options.params
} else {
// default, assume this is JSON
_headers['Content-Type'] = 'application/json'
body = JSON.stringify(options.args)
body = JSON.stringify(options.params)
}
}

try {
const response = await this.fetch(`${this.url}/${functionId}`, {
method: 'POST',
body: JSON.stringify(options.args),
body,
headers: { ..._headers, ...this.headers, ...options.headers }
})

if (!response.ok) {
throw new SQLiteCloudError(`Failed to invoke function: ${response.statusText}`)
}

let responseType = (response.headers.get('Content-Type') ?? 'text/plain').split(';')[0].trim()
let data: any
if (responseType === 'application/json') {
data = await response.json()
} else if (responseType === 'application/octet-stream') {
data = await response.blob()
} else if (responseType === 'text/event-stream') {
data = response
} else if (responseType === 'multipart/form-data') {
data = await response.formData()
} else {
data = await response.text()
}
return { ...data, error: null }
return { error: null, ...(await response.json()) }
} catch (error) {
return { data: null, error }
}
Expand Down
44 changes: 44 additions & 0 deletions src/packages/test/functions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

// Test functions client
// invoke

import { CHINOOK_API_KEY, CHINOOK_DATABASE_URL } from "../../../test/shared"
import { FunctionsClient } from "../_functions/FunctionsClient"

const TEST_SQL_FUNCTION_ID = 'test-1-sql'
const TEST_JS_FUNCTION_ID = 'test-1-js'

const TEST_FUNCTION_ARG = {
filter: 'a',
limit: 10
}

const functions = new FunctionsClient(CHINOOK_DATABASE_URL)

describe('FunctionsClient', () => {
it('should invoke a JS function', async () => {

const { data, error } = await functions.invoke(TEST_JS_FUNCTION_ID, {
params: TEST_FUNCTION_ARG,
headers: {
'Authorization': `Bearer ${CHINOOK_API_KEY}`
}
})
expect(data.message).toBeDefined()
expect(data.result).toBeDefined()
expect(error).toBeNull()
})

it('should invoke a SQL function', async () => {
const { data, error } = await functions.invoke(TEST_SQL_FUNCTION_ID, {
params: TEST_FUNCTION_ARG,
headers: {
'Authorization': `Bearer ${CHINOOK_API_KEY}`
}
})
expect(data).toBeDefined()
expect(data.length > 0).toBeTruthy()
expect(error).toBeNull()
})
})

6 changes: 3 additions & 3 deletions src/packages/utils/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ export const resolveFetch = (customFetch?: Fetch): Fetch => {
if (customFetch) {
_fetch = customFetch
} else if (typeof fetch !== 'undefined') {
_fetch = nodeFetch as unknown as Fetch
} else {
_fetch = fetch
} else {
_fetch = nodeFetch as unknown as Fetch
}
return (...args: Parameters<Fetch>) => _fetch(...args)
return _fetch
}

export const resolveHeadersConstructor = () => {
Expand Down
8 changes: 4 additions & 4 deletions src/packages/weblite/WebliteClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class WebliteClient {
) {
this.baseUrl = getAPIUrl(connectionString, 'weblite')
this.fetch = options?.fetch || fetchWithAuth(connectionString)
this.headers = { ...options.headers }
this.headers = { ...DEFAULT_HEADERS, ...options.headers }
this._defaultDatabase = getDefaultDatabase(connectionString)
}

Expand Down Expand Up @@ -120,7 +120,7 @@ export class WebliteClient {
const filenamePath = encodeURIComponent(filename)
const url = `${this.baseUrl}/${filenamePath}`
try {
const response = await this.fetch(url, { method: 'GET', headers: { ...this.headers } })
const response = await this.fetch(url, { method: 'GET', headers: this.headers })
if (!response.ok) {
throw new SQLiteCloudError(`Failed to download database: ${response.statusText}`)
}
Expand All @@ -141,7 +141,7 @@ export class WebliteClient {
url,
{
method: 'DELETE',
headers: { ...this.headers }
headers: this.headers
}
)
if (!response.ok) {
Expand All @@ -156,7 +156,7 @@ export class WebliteClient {
async listDatabases() {
const url = `${this.baseUrl}/databases`
try {
const response = await this.fetch(url, { method: 'GET', headers: { ...this.headers } })
const response = await this.fetch(url, { method: 'GET', headers: this.headers })
if (!response.ok) {
throw new SQLiteCloudError(`Failed to list databases: ${response.statusText}`)
}
Expand Down

0 comments on commit c6c85b0

Please sign in to comment.