diff --git a/.changeset/tough-needles-rest.md b/.changeset/tough-needles-rest.md new file mode 100644 index 0000000..22e7f8f --- /dev/null +++ b/.changeset/tough-needles-rest.md @@ -0,0 +1,5 @@ +--- +"@crbroughton/sibyl": minor +--- + +Implement limited search - The Select function now support limited queries diff --git a/README.md b/README.md index 649dae1..5fb0343 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,7 @@ const test = Insert('firstTable', insertions) When selecting entries from the database, you can utilise the `Select` function to retrieve an array of type-safe entries, based from the generic interface -you have supplied to Sybil main function (see above `tableRowType`). +you have supplied to Sibyl main function (see above `tableRowType`). ```typescript selection.value = Select('firstTable', { diff --git a/bun.lockb b/bun.lockb index e05da3c..27e12e4 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 516b379..bbb2d6b 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "devDependencies": { "@antfu/eslint-config": "^2.8.0", "@changesets/cli": "^2.27.1", + "@crbroughton/ts-test-utils": "^0.6.0", "@types/bun": "latest", "eslint": "^8.57.0" } diff --git a/playground/src/components/DemoTable.vue b/playground/src/components/DemoTable.vue index cdfe59e..e2a4e40 100644 --- a/playground/src/components/DemoTable.vue +++ b/playground/src/components/DemoTable.vue @@ -169,7 +169,7 @@ const amountOfOrders = computed(() => { - Sybil Table + Sibyl Table Order amount: {{ amountOfOrders }} diff --git a/src/bun/README.md b/src/bun/README.md index 649dae1..b7ebefa 100644 --- a/src/bun/README.md +++ b/src/bun/README.md @@ -93,6 +93,8 @@ functions: - `Create` - Creates and returns a new entry into your selected table - `Insert` - Allows you to provide an array of insertable entries into your selected table - `Select` - Returns a type-safe array of entries from the selected table +- `LimitedSelect` - Returns a type-safe, limited array of entries from +the selected table - `All` - Returns all entries from the selected table - `Update` Updates and returns a single entry from the selected table - `Delete` - Deletes an entry from a selected table @@ -169,7 +171,7 @@ const test = Insert('firstTable', insertions) When selecting entries from the database, you can utilise the `Select` function to retrieve an array of type-safe entries, based from the generic interface -you have supplied to Sybil main function (see above `tableRowType`). +you have supplied to Sibyl main function (see above `tableRowType`). ```typescript selection.value = Select('firstTable', { @@ -182,6 +184,26 @@ selection.value = Select('firstTable', { }) ``` +### Selecting limited entries from the DB + +When selecting entries from the database but you want to be selective about the responses values, you can utilise the `LimitedSelect` function +to retrieve an array of type-safe entries, based from the generic interface +you have supplied to Sibyl main function (see above `tableRowType`). + +The core difference here is that the `where` clause now also controls +what values you get back. + +```typescript +selection.value = LimitedSelect('firstTable', { + where: { + id: 1, + name: "Craig", // can combine multiple where clauses + }, + limit: 20, // limit the response from Sibyl + offset: 10, // offset the response, useful for pagination +}) +``` + #### OR Selection When selecting entries from the database, the `Select` function, by diff --git a/src/bun/index.ts b/src/bun/index.ts index f4aeb4b..c7b0136 100644 --- a/src/bun/index.ts +++ b/src/bun/index.ts @@ -2,6 +2,7 @@ import type { Database, SQLQueryBindings } from 'bun:sqlite' import type { DeleteArgs, MappedTable, + ReplaceValues, SelectArgs, SibylResponse, Sort, @@ -17,26 +18,37 @@ import { export default async function Sibyl>(db: Database) { type TableKeys = keyof T -type AccessTable = T[I] -function createTable(table: T, tableRow: MappedTable>) { +type AccessTable = T[TableKeys] +function createTable(table: T, tableRow: MappedTable) { const statement = convertCreateTableStatement(tableRow) db.query(`CREATE TABLE ${String(table)} (${statement})`).run() } -function Insert(table: K, rows: AccessTable[]) { +function Insert(table: K, rows: AccessTable[]) { const statement = formatInsertStatement(String(table), rows) db.run(statement) } -function Select(table: T, args: SelectArgs>>) { + +function LimitedSelect(table: T, args: SelectArgs>) { + const query = buildSelectQuery(String(table), { ...args, limited: true }) + const record = db.query>, SQLQueryBindings[]>(query) + + if (record !== undefined) + return record.all() + + return undefined +} + +function Select(table: T, args: SelectArgs>) { const query = buildSelectQuery(String(table), args) - const record = db.query>, SQLQueryBindings[]>(query) + const record = db.query, SQLQueryBindings[]>(query) if (record !== undefined) return record.all() return undefined } -function Create(table: T, entry: AccessTable) { +function Create(table: T, entry: AccessTable) { const statement = formatInsertStatement(String(table), [entry]) db.run(statement) const result = Select(table, { @@ -49,7 +61,7 @@ function Create(table: T, entry: AccessTable) { return undefined } -function All(table: K, args?: { sort: Sort>> }) { +function All(table: K, args?: { sort: Sort> }) { let query = `SELECT * from ${String(table)}` if (args !== undefined && args.sort) { @@ -60,7 +72,7 @@ function All(table: K, args?: { sort: Sort>, SQLQueryBindings[]>(query) + const record = db.query, SQLQueryBindings[]>(query) if (record !== undefined) return record.all() @@ -68,7 +80,7 @@ function All(table: K, args?: { sort: Sort(table: K, args: UpdateArgs>) { +function Update(table: K, args: UpdateArgs) { const query = buildUpdateQuery(table, args) db.exec(query) @@ -81,13 +93,14 @@ function Update(table: K, args: UpdateArgs>) return undefined } -function Delete(table: K, args: DeleteArgs>) { +function Delete(table: K, args: DeleteArgs) { db.run(`DELETE FROM ${String(table)} WHERE ${objectToWhereClause(args.where)}`) } return { createTable, Insert, + LimitedSelect, Select, Create, All, diff --git a/src/bun/tests/limitedSelect.test.ts b/src/bun/tests/limitedSelect.test.ts new file mode 100644 index 0000000..c97c12d --- /dev/null +++ b/src/bun/tests/limitedSelect.test.ts @@ -0,0 +1,86 @@ +/* eslint-disable unused-imports/no-unused-vars */ +import { describe, expect, it } from 'bun:test' +import { Database } from 'bun:sqlite' +import type { Equals, Expect } from '@crbroughton/ts-test-utils' +import Sibyl from '../index' +import type { SibylResponse } from '../../types' + +interface firstTable { + id: number + name: string + location: string + hasReadTheReadme: boolean +} +interface Tables { + firstTable: firstTable +} + +describe('LimitedSelect tests', () => { + it('selects an entry from the DB, using the limited functionality', async () => { + const db = new Database(':memory:') + const { createTable, Insert, LimitedSelect } = await Sibyl(db) + + createTable('firstTable', { + id: { + autoincrement: true, + type: 'INTEGER', + primary: true, + unique: true, + }, + name: { + type: 'char', + size: 10, + }, + hasReadTheReadme: { + type: 'bool', + }, + location: { + type: 'char', + size: 10, + }, + }) + + Insert('firstTable', [ + { + id: 1, + hasReadTheReadme: true, + location: 'Brighton', + name: 'Craig', + }, + { + id: 2, + hasReadTheReadme: false, + location: 'Leeds', + name: 'Bob', + }, + { + id: 3, + hasReadTheReadme: true, + location: 'Brighton', + name: 'David', + }, + ]) + + const actual = LimitedSelect('firstTable', { + where: { + name: 'Craig', + hasReadTheReadme: 1, + }, + }) + + // Type tests + const singluarActual = actual![0] + type ActualType = typeof singluarActual + type ExpectedType = Omit, 'id' | 'location'> + type ResultType = Expect> + // ^? + + const expectation: ExpectedType[] = [ + { + hasReadTheReadme: 1, + name: 'Craig', + }, + ] + expect(actual).toStrictEqual(expectation) + }) +}) diff --git a/src/libsql/README.md b/src/libsql/README.md index 649dae1..b7ebefa 100644 --- a/src/libsql/README.md +++ b/src/libsql/README.md @@ -93,6 +93,8 @@ functions: - `Create` - Creates and returns a new entry into your selected table - `Insert` - Allows you to provide an array of insertable entries into your selected table - `Select` - Returns a type-safe array of entries from the selected table +- `LimitedSelect` - Returns a type-safe, limited array of entries from +the selected table - `All` - Returns all entries from the selected table - `Update` Updates and returns a single entry from the selected table - `Delete` - Deletes an entry from a selected table @@ -169,7 +171,7 @@ const test = Insert('firstTable', insertions) When selecting entries from the database, you can utilise the `Select` function to retrieve an array of type-safe entries, based from the generic interface -you have supplied to Sybil main function (see above `tableRowType`). +you have supplied to Sibyl main function (see above `tableRowType`). ```typescript selection.value = Select('firstTable', { @@ -182,6 +184,26 @@ selection.value = Select('firstTable', { }) ``` +### Selecting limited entries from the DB + +When selecting entries from the database but you want to be selective about the responses values, you can utilise the `LimitedSelect` function +to retrieve an array of type-safe entries, based from the generic interface +you have supplied to Sibyl main function (see above `tableRowType`). + +The core difference here is that the `where` clause now also controls +what values you get back. + +```typescript +selection.value = LimitedSelect('firstTable', { + where: { + id: 1, + name: "Craig", // can combine multiple where clauses + }, + limit: 20, // limit the response from Sibyl + offset: 10, // offset the response, useful for pagination +}) +``` + #### OR Selection When selecting entries from the database, the `Select` function, by diff --git a/src/libsql/index.ts b/src/libsql/index.ts index c3b6c51..4ac449f 100644 --- a/src/libsql/index.ts +++ b/src/libsql/index.ts @@ -1,5 +1,13 @@ import type { Database } from 'libsql' -import type { DeleteArgs, MappedTable, SelectArgs, SibylResponse, Sort, UpdateArgs } from '../types' +import type { + DeleteArgs, + MappedTable, + ReplaceValues, + SelectArgs, + SibylResponse, + Sort, + UpdateArgs, +} from '../types' import { buildSelectQuery, buildUpdateQuery, @@ -10,20 +18,30 @@ import { export default async function Sibyl>(db: Database) { type TableKeys = keyof T -type AccessTable = T[I] -function createTable(table: T, tableRow: MappedTable>) { +type AccessTable = T[TableKeys] +function createTable(table: T, tableRow: MappedTable) { const statement = convertCreateTableStatement(tableRow) db.exec(`CREATE TABLE ${String(table)} (${statement});`) } -function Insert(table: K, rows: AccessTable[]) { +function Insert(table: K, rows: AccessTable[]) { const statement = formatInsertStatementLibSQL(String(table), rows) db.exec(statement) } -function Select(table: T, args: SelectArgs>>) { +function LimitedSelect(table: T, args: SelectArgs>) { + const query = buildSelectQuery(String(table), { ...args, limited: true }) + const record = db.prepare(query).all() as SibylResponse>[] + + if (record !== undefined) + return record + + return undefined +} + +function Select(table: T, args: SelectArgs>) { const query = buildSelectQuery(String(table), args) - const record = db.prepare(query).all() as SibylResponse>[] + const record = db.prepare(query).all() as SibylResponse[] if (record !== undefined) return record @@ -31,7 +49,7 @@ function Select(table: T, args: SelectArgs(table: T, entry: AccessTable) { +function Create(table: T, entry: AccessTable) { const statement = formatInsertStatementLibSQL(String(table), [entry]) db.exec(statement) @@ -45,7 +63,7 @@ function Create(table: T, entry: AccessTable) { return undefined } -function All(table: K, args?: { sort: Sort>> }) { +function All(table: K, args?: { sort: Sort> }) { let query = `SELECT * from ${String(table)}` if (args !== undefined && args.sort) { @@ -56,7 +74,7 @@ function All(table: K, args?: { sort: Sort>[] + const record = db.prepare(query).all() as SibylResponse[] if (record !== undefined) return record @@ -64,7 +82,7 @@ function All(table: K, args?: { sort: Sort(table: K, args: UpdateArgs>) { +function Update(table: K, args: UpdateArgs) { const query = buildUpdateQuery(table, args) db.exec(query) @@ -78,12 +96,13 @@ function Update(table: K, args: UpdateArgs>) return undefined } -function Delete(table: K, args: DeleteArgs>) { +function Delete(table: K, args: DeleteArgs) { db.exec(`DELETE FROM ${String(table)} WHERE ${objectToWhereClause(args.where)}`) } return { createTable, + LimitedSelect, Select, All, Insert, diff --git a/src/libsql/tests/limitedSelect.test.ts b/src/libsql/tests/limitedSelect.test.ts new file mode 100644 index 0000000..ffcd4d7 --- /dev/null +++ b/src/libsql/tests/limitedSelect.test.ts @@ -0,0 +1,86 @@ +/* eslint-disable unused-imports/no-unused-vars */ +import { describe, expect, it } from 'bun:test' +import Database from 'libsql' +import type { Equals, Expect } from '@crbroughton/ts-test-utils' +import Sibyl from '../index' +import type { SibylResponse } from '../../types' + +interface firstTable { + id: number + name: string + location: string + hasReadTheReadme: boolean +} +interface Tables { + firstTable: firstTable +} + +describe('LimitedSelect tests', () => { + it('selects an entry from the DB, using the limited functionality', async () => { + const db = new Database(':memory:') + const { createTable, Insert, LimitedSelect } = await Sibyl(db) + + createTable('firstTable', { + id: { + autoincrement: true, + type: 'INTEGER', + primary: true, + unique: true, + }, + name: { + type: 'char', + size: 10, + }, + hasReadTheReadme: { + type: 'bool', + }, + location: { + type: 'char', + size: 10, + }, + }) + + Insert('firstTable', [ + { + id: 1, + hasReadTheReadme: true, + location: 'Brighton', + name: 'Craig', + }, + { + id: 2, + hasReadTheReadme: false, + location: 'Leeds', + name: 'Bob', + }, + { + id: 3, + hasReadTheReadme: true, + location: 'Brighton', + name: 'David', + }, + ]) + + const actual = LimitedSelect('firstTable', { + where: { + name: 'Craig', + hasReadTheReadme: 1, + }, + }) + + // Type tests + const singluarActual = actual![0] + type ActualType = typeof singluarActual + type ExpectedType = Omit, 'id' | 'location'> + type ResultType = Expect> + // ^? + + const expectation: ExpectedType[] = [ + { + hasReadTheReadme: 1, + name: 'Craig', + }, + ] + expect(actual).toStrictEqual(expectation) + }) +}) diff --git a/src/sibylLib.ts b/src/sibylLib.ts index bffae0d..b48fa65 100644 --- a/src/sibylLib.ts +++ b/src/sibylLib.ts @@ -92,14 +92,28 @@ export function convertBooleanValues(arr: T[]) { }) } -export function buildSelectQuery(table: string, args: SelectArgs) { +export function buildSelectQuery(table: string, args: SelectArgs | SelectArgs & { limited: boolean }) { let query: string = '' - if (args.where.OR === undefined) - query = `SELECT * from ${table} WHERE ${objectToWhereClause(args.where)}` + if ('limited' in args) { + if (args.limited === true) { + let selectedKeys = '' + for (const [key] of Object.entries(args.where)) + selectedKeys += `${key}, ` - if (args.where.OR !== undefined) - query = `SELECT * from ${table} WHERE ${objectToOrClause(args.where.OR)}` + selectedKeys = selectedKeys.slice(0, -2) + + query = `SELECT ${selectedKeys} from ${table} WHERE ${objectToWhereClause(args.where)}` + } + } + else { + query += 'SELECT * ' + if (args.where.OR === undefined) + query += `from ${table} WHERE ${objectToWhereClause(args.where)}` + + if (args.where.OR !== undefined) + query += `from ${table} WHERE ${objectToOrClause(args.where.OR)}` + } if (args.offset && !args.limit) query += ` LIMIT -1 OFFSET ${args.offset}` diff --git a/src/sqljs/README.md b/src/sqljs/README.md index 649dae1..b7ebefa 100644 --- a/src/sqljs/README.md +++ b/src/sqljs/README.md @@ -93,6 +93,8 @@ functions: - `Create` - Creates and returns a new entry into your selected table - `Insert` - Allows you to provide an array of insertable entries into your selected table - `Select` - Returns a type-safe array of entries from the selected table +- `LimitedSelect` - Returns a type-safe, limited array of entries from +the selected table - `All` - Returns all entries from the selected table - `Update` Updates and returns a single entry from the selected table - `Delete` - Deletes an entry from a selected table @@ -169,7 +171,7 @@ const test = Insert('firstTable', insertions) When selecting entries from the database, you can utilise the `Select` function to retrieve an array of type-safe entries, based from the generic interface -you have supplied to Sybil main function (see above `tableRowType`). +you have supplied to Sibyl main function (see above `tableRowType`). ```typescript selection.value = Select('firstTable', { @@ -182,6 +184,26 @@ selection.value = Select('firstTable', { }) ``` +### Selecting limited entries from the DB + +When selecting entries from the database but you want to be selective about the responses values, you can utilise the `LimitedSelect` function +to retrieve an array of type-safe entries, based from the generic interface +you have supplied to Sibyl main function (see above `tableRowType`). + +The core difference here is that the `where` clause now also controls +what values you get back. + +```typescript +selection.value = LimitedSelect('firstTable', { + where: { + id: 1, + name: "Craig", // can combine multiple where clauses + }, + limit: 20, // limit the response from Sibyl + offset: 10, // offset the response, useful for pagination +}) +``` + #### OR Selection When selecting entries from the database, the `Select` function, by diff --git a/src/sqljs/index.ts b/src/sqljs/index.ts index 1a881db..ed2a5b8 100644 --- a/src/sqljs/index.ts +++ b/src/sqljs/index.ts @@ -1,5 +1,13 @@ import type { Database } from 'sql.js' -import type { DeleteArgs, MappedTable, SelectArgs, SibylResponse, Sort, UpdateArgs } from '../types' +import type { + DeleteArgs, + MappedTable, + ReplaceValues, + SelectArgs, + SibylResponse, + Sort, + UpdateArgs, +} from '../types' import { buildSelectQuery, buildUpdateQuery, @@ -12,23 +20,37 @@ import { export default async function Sibyl>(db: Database) { type TableKeys = keyof T -type AccessTable = T[I] -function createTable(table: T, tableRow: MappedTable>) { +type AccessTable = T[TableKeys] +function createTable(table: T, tableRow: MappedTable) { const statement = convertCreateTableStatement(tableRow) db.run(`CREATE TABLE ${String(table)} (${statement});`) } -function Insert(table: K, rows: AccessTable[]) { +function Insert(table: K, rows: AccessTable[]) { const statement = formatInsertStatement(String(table), rows) db.run(statement) } -function Select(table: T, args: SelectArgs>>) { +function LimitedSelect(table: T, args: SelectArgs>) { + const query = buildSelectQuery(String(table), { ...args, limited: true }) + const record = db.exec(query) + + if (record[0]) { + return convertBooleanValues(convertToObjects({ + columns: record[0].columns, + values: record[0].values, + })) as SibylResponse>[] + } + + return undefined +} + +function Select(table: T, args: SelectArgs>) { const query = buildSelectQuery(String(table), args) const record = db.exec(query) if (record[0]) { - return convertBooleanValues(convertToObjects>({ + return convertBooleanValues(convertToObjects({ columns: record[0].columns, values: record[0].values, })) @@ -37,7 +59,7 @@ function Select(table: T, args: SelectArgs(table: T, entry: AccessTable) { +function Create(table: T, entry: AccessTable) { const statement = formatInsertStatement(String(table), [entry]) db.run(statement) const result = Select(table, { @@ -50,7 +72,7 @@ function Create(table: T, entry: AccessTable) { return undefined } -function All(table: K, args?: { sort: Sort>> }) { +function All(table: K, args?: { sort: Sort> }) { let query = `SELECT * from ${String(table)}` if (args !== undefined && args.sort) { @@ -64,7 +86,7 @@ function All(table: K, args?: { sort: Sort>({ + return convertBooleanValues(convertToObjects({ columns: record[0].columns, values: record[0].values, })) @@ -73,7 +95,7 @@ function All(table: K, args?: { sort: Sort(table: K, args: UpdateArgs>) { +function Update(table: K, args: UpdateArgs) { const query = buildUpdateQuery(table, args) db.exec(query) @@ -87,12 +109,13 @@ function Update(table: K, args: UpdateArgs>) return undefined } -function Delete(table: K, args: DeleteArgs>) { +function Delete(table: K, args: DeleteArgs) { db.run(`DELETE FROM ${String(table)} WHERE ${objectToWhereClause(args.where)}`) } return { createTable, + LimitedSelect, Select, All, Insert, diff --git a/src/sqljs/package.json b/src/sqljs/package.json index 469b4a4..c83cc8a 100644 --- a/src/sqljs/package.json +++ b/src/sqljs/package.json @@ -23,7 +23,8 @@ "dist" ], "scripts": { - "build": "bun run build.ts", + "typecheck": "tsc --skipLibCheck --noEmit", + "build": "bun run typecheck && bun run build.ts", "lint": "eslint .", "lint:fix": "eslint . --fix", "changeset": "npx changeset", diff --git a/src/sqljs/tests/buildSelectQuery.test.ts b/src/sqljs/tests/buildSelectQuery.test.ts index d33e48a..8be045e 100644 --- a/src/sqljs/tests/buildSelectQuery.test.ts +++ b/src/sqljs/tests/buildSelectQuery.test.ts @@ -232,6 +232,19 @@ describe('buildSelectQuery tests', () => { const expectation = `SELECT * from test WHERE id = '1' OR id = '2' ORDER BY id DESC, name ASC;` + expect(actual).toStrictEqual(expectation) + }) + it('builds a SELECT query with a single where clause, using the limited option', async () => { + const actual = buildSelectQuery('test', { + where: { + id: 1, + name: 'Craig', + }, + limited: true, + }) + + const expectation = `SELECT id, name from test WHERE id = '1' AND name = 'Craig';` + expect(actual).toStrictEqual(expectation) }) }) diff --git a/src/sqljs/tests/limitedSelect.test.ts b/src/sqljs/tests/limitedSelect.test.ts new file mode 100644 index 0000000..4b6c60a --- /dev/null +++ b/src/sqljs/tests/limitedSelect.test.ts @@ -0,0 +1,91 @@ +/* eslint-disable unused-imports/no-unused-vars */ +import { describe, expect, it } from 'bun:test' +import sql from 'sql.js' +import type { Equals, Expect } from '@crbroughton/ts-test-utils' +import Sibyl from '../index' +import type { SibylResponse } from '../../types' + +interface firstTable { + id: number + name: string + location: string + hasReadTheReadme: boolean +} +interface Tables { + firstTable: firstTable +} + +describe('LimitedSelect tests', () => { + it('selects an entry from the DB, using the limited functionality', async () => { + const SQL = await sql({ + locateFile: () => { + return 'playground/public/sql-wasm.wasm' + }, + }) + const db = new SQL.Database() + const { createTable, Insert, LimitedSelect } = await Sibyl(db) + + createTable('firstTable', { + id: { + autoincrement: true, + type: 'INTEGER', + primary: true, + unique: true, + }, + name: { + type: 'char', + size: 10, + }, + hasReadTheReadme: { + type: 'bool', + }, + location: { + type: 'char', + size: 10, + }, + }) + + Insert('firstTable', [ + { + id: 1, + hasReadTheReadme: true, + location: 'Brighton', + name: 'Craig', + }, + { + id: 2, + hasReadTheReadme: false, + location: 'Leeds', + name: 'Bob', + }, + { + id: 3, + hasReadTheReadme: true, + location: 'Brighton', + name: 'David', + }, + ]) + + const actual = LimitedSelect('firstTable', { + where: { + name: 'Craig', + hasReadTheReadme: 1, + }, + }) + + // Type tests + const singluarActual = actual![0] + type ActualType = typeof singluarActual + type ExpectedType = Omit, 'id' | 'location'> + type ResultType = Expect> + // ^? + + const expectation: ExpectedType[] = [ + { + hasReadTheReadme: 1, + name: 'Craig', + }, + ] + expect(actual).toStrictEqual(expectation) + }) +}) diff --git a/src/sqljs/tests/select.test.ts b/src/sqljs/tests/select.test.ts index 01d865b..0d46a20 100644 --- a/src/sqljs/tests/select.test.ts +++ b/src/sqljs/tests/select.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from 'bun:test' import sql from 'sql.js' +import type { Equals, Expect } from '@crbroughton/ts-test-utils' import Sibyl from '../index' import type { SibylResponse } from '../../types' diff --git a/src/sqljs/tests/types/ReplaceValues.ts b/src/sqljs/tests/types/ReplaceValues.ts new file mode 100644 index 0000000..85a313a --- /dev/null +++ b/src/sqljs/tests/types/ReplaceValues.ts @@ -0,0 +1,21 @@ +/* eslint-disable unused-imports/no-unused-vars */ +import type { Equals, Expect } from '@crbroughton/ts-test-utils' +import type { ReplaceValues } from '../../../types' + +interface Replacing { + id: 1 + name: 'Craig' +} + +interface Replaced { + id: number + name: string +} + +type Actual = ReplaceValues +interface Expectation { + id: 1 + name: 'Craig' +} +type ReplaceValuesResult = Expect> +// ^? diff --git a/src/types.ts b/src/types.ts index 91e83c1..55d9503 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,3 +75,7 @@ export interface DataStructure { columns: string[] values: any[][] } + +export type ReplaceValues = { + [K in keyof T]: K extends keyof U ? U[K] : T[K] +} diff --git a/tsconfig.json b/tsconfig.json index d4dabb4..215bd85 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,5 +23,6 @@ "noEmit": true, "verbatimModuleSyntax": true, "skipLibCheck": true - } + }, + "exclude": ["playground", "libsql-playground", "bun-playground"] }