Skip to content

Commit

Permalink
Merge pull request #64 from CRBroughton/63-offer-limited-select-state…
Browse files Browse the repository at this point in the history
…ments-instead-of-performing-select-for-every-select-all-query

feat: ✨ Implement limited search
  • Loading branch information
CRBroughton authored May 11, 2024
2 parents 183d9ee + 17b5e48 commit 04358df
Show file tree
Hide file tree
Showing 21 changed files with 489 additions and 44 deletions.
5 changes: 5 additions & 0 deletions .changeset/tough-needles-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@crbroughton/sibyl": minor
---

Implement limited search - The Select function now support limited queries
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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', {
Expand Down
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
2 changes: 1 addition & 1 deletion playground/src/components/DemoTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ const amountOfOrders = computed(() => {
<Card class="w-full lg:w-[980px]">
<CardHeader>
<CardTitle>
Sybil Table
Sibyl Table
</CardTitle>
<CardDescription>
Order amount: {{ amountOfOrders }}
Expand Down
24 changes: 23 additions & 1 deletion src/bun/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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', {
Expand All @@ -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
Expand Down
33 changes: 23 additions & 10 deletions src/bun/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Database, SQLQueryBindings } from 'bun:sqlite'
import type {
DeleteArgs,
MappedTable,
ReplaceValues,
SelectArgs,
SibylResponse,
Sort,
Expand All @@ -17,26 +18,37 @@ import {

export default async function Sibyl<T extends Record<string, any>>(db: Database) {
type TableKeys = keyof T
type AccessTable<I extends keyof T> = T[I]
function createTable<T extends TableKeys>(table: T, tableRow: MappedTable<AccessTable<T>>) {
type AccessTable = T[TableKeys]
function createTable<T extends TableKeys>(table: T, tableRow: MappedTable<AccessTable>) {
const statement = convertCreateTableStatement(tableRow)
db.query(`CREATE TABLE ${String(table)} (${statement})`).run()
}

function Insert<K extends TableKeys>(table: K, rows: AccessTable<K>[]) {
function Insert<K extends TableKeys>(table: K, rows: AccessTable[]) {
const statement = formatInsertStatement(String(table), rows)
db.run(statement)
}
function Select<T extends TableKeys>(table: T, args: SelectArgs<SibylResponse<AccessTable<T>>>) {

function LimitedSelect<T extends TableKeys, U = AccessTable>(table: T, args: SelectArgs<SibylResponse<U>>) {
const query = buildSelectQuery(String(table), { ...args, limited: true })
const record = db.query<SibylResponse<ReplaceValues<U, AccessTable>>, SQLQueryBindings[]>(query)

if (record !== undefined)
return record.all()

return undefined
}

function Select<T extends TableKeys>(table: T, args: SelectArgs<SibylResponse<AccessTable>>) {
const query = buildSelectQuery(String(table), args)
const record = db.query<SibylResponse<AccessTable<T>>, SQLQueryBindings[]>(query)
const record = db.query<SibylResponse<AccessTable>, SQLQueryBindings[]>(query)

if (record !== undefined)
return record.all()

return undefined
}
function Create<T extends TableKeys>(table: T, entry: AccessTable<T>) {
function Create<T extends TableKeys>(table: T, entry: AccessTable) {
const statement = formatInsertStatement(String(table), [entry])
db.run(statement)
const result = Select(table, {
Expand All @@ -49,7 +61,7 @@ function Create<T extends TableKeys>(table: T, entry: AccessTable<T>) {
return undefined
}

function All<K extends TableKeys>(table: K, args?: { sort: Sort<Partial<AccessTable<K>>> }) {
function All<K extends TableKeys>(table: K, args?: { sort: Sort<Partial<AccessTable>> }) {
let query = `SELECT * from ${String(table)}`

if (args !== undefined && args.sort) {
Expand All @@ -60,15 +72,15 @@ function All<K extends TableKeys>(table: K, args?: { sort: Sort<Partial<AccessTa
query += orders.join(', ')
}

const record = db.query<SibylResponse<AccessTable<K>>, SQLQueryBindings[]>(query)
const record = db.query<SibylResponse<AccessTable>, SQLQueryBindings[]>(query)

if (record !== undefined)
return record.all()

return undefined
}

function Update<K extends TableKeys>(table: K, args: UpdateArgs<AccessTable<K>>) {
function Update<K extends TableKeys>(table: K, args: UpdateArgs<AccessTable>) {
const query = buildUpdateQuery(table, args)
db.exec(query)

Expand All @@ -81,13 +93,14 @@ function Update<K extends TableKeys>(table: K, args: UpdateArgs<AccessTable<K>>)

return undefined
}
function Delete<K extends TableKeys>(table: K, args: DeleteArgs<AccessTable<K>>) {
function Delete<K extends TableKeys>(table: K, args: DeleteArgs<AccessTable>) {
db.run(`DELETE FROM ${String(table)} WHERE ${objectToWhereClause(args.where)}`)
}

return {
createTable,
Insert,
LimitedSelect,
Select,
Create,
All,
Expand Down
86 changes: 86 additions & 0 deletions src/bun/tests/limitedSelect.test.ts
Original file line number Diff line number Diff line change
@@ -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<Tables>(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<SibylResponse<firstTable>, 'id' | 'location'>
type ResultType = Expect<Equals<ActualType, ExpectedType>>
// ^?

const expectation: ExpectedType[] = [
{
hasReadTheReadme: 1,
name: 'Craig',
},
]
expect(actual).toStrictEqual(expectation)
})
})
24 changes: 23 additions & 1 deletion src/libsql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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', {
Expand All @@ -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
Expand Down
Loading

0 comments on commit 04358df

Please sign in to comment.