Skip to content

Commit

Permalink
add mutation
Browse files Browse the repository at this point in the history
  • Loading branch information
zfben committed Feb 1, 2025
1 parent 78dc2b3 commit 70cf01c
Show file tree
Hide file tree
Showing 11 changed files with 300 additions and 51 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@ jobs:
PG_CONNECTION: postgresql://postgres:postgres@localhost:5432
- uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOVTOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
- uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
dist
coverage
*.xml
10 changes: 10 additions & 0 deletions src/__tests__/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import { type Client, createClient } from '../client'
import { createTestingPostgres } from './utils'
import { QueryBuilder } from '../query-builder'
import { isAsyncFunction } from 'node:util/types'

describe('client', () => {
let client: Client
Expand Down Expand Up @@ -42,4 +44,12 @@ describe('client', () => {
])
})
})

it('query', () => {
expect(client.query('users')).toBeInstanceOf(QueryBuilder)
})

it('quit', async () => {
expect(isAsyncFunction(client.quit)).toBeTruthy()
})
})
11 changes: 11 additions & 0 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { describe, expect, it } from 'vitest'
import * as TypedPg from '../index'

describe('TypedPg', () => {
it('should be defined', () => {
expect(Object.keys(TypedPg)).toEqual([
'Client',
'createClient',
])
})
})
79 changes: 79 additions & 0 deletions src/__tests__/query-builder/mutation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'
import { type Client, createClient } from '../../client'
import { QueryBuilder } from '../../query-builder'
import { createTestingPostgres } from '../utils'

describe('QueryBuilder/mutation', () => {
let client: Client

beforeAll(async () => {
client = createClient(createTestingPostgres())

await client.raw`
CREATE TABLE mutation (
id SERIAL PRIMARY KEY,
name TEXT,
metadata JSONB
);
`
})

afterAll(async () => {
await client.raw`DROP TABLE mutation`

await client.quit()
})

beforeEach(async () => {
await client.raw`TRUNCATE mutation`

await client.raw`
INSERT INTO mutation (id, name, metadata) VALUES (1, 'Alice', '{"age":100}'), (2, 'Bob', '{}');
`
})

describe('insert', () => {
it('inserts a row', async () => {
const returning = await new QueryBuilder(client, 'mutation').insert(
{
id: 3,
name: 'Charlie',
metadata: { age: 50 },
},
{ returning: ['name', 'metadata'] }
)

expect(returning).toEqual([{ name: 'Charlie', metadata: { age: 50 } }])

const result = await new QueryBuilder(client, 'mutation').pluck('name')

expect(result).toEqual(['Alice', 'Bob', 'Charlie'])
})
})

describe('update', () => {
it('updates a row', async () => {
const returning = await new QueryBuilder(client, 'mutation')
.where('name', 'Alice')
.update({ name: 'David' }, { returning: ['name'] })

expect(returning).toEqual([{ name: 'David' }])

const result = await new QueryBuilder(client, 'mutation').pluck('name')

expect(result).toEqual(['Bob', 'David'])
})
})

describe('delete', () => {
it('deletes a row', async () => {
await new QueryBuilder(client, 'mutation')
.where('name', 'Alice')
.delete()

const result = await new QueryBuilder(client, 'mutation').pluck('name')

expect(result).toEqual(['Bob'])
})
})
})
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import { type Client, createClient } from '../client'
import { QueryBuilder } from '../query-builder'
import { createTestingPostgres } from './utils'
import { type Client, createClient } from '../../client'
import { QueryBuilder } from '../../query-builder'
import { createTestingPostgres } from '../utils'

describe('QueryBuilder', () => {
describe('QueryBuilder/query', () => {
let client: Client

beforeAll(async () => {
client = createClient(createTestingPostgres())

await client.raw`
CREATE TABLE users (
CREATE TABLE query (
id SERIAL PRIMARY KEY,
name TEXT,
metadata JSONB
);
`

await client.raw`
INSERT INTO users (id, name, metadata) VALUES (1, 'Alice', '{"age":100}'), (2, 'Bob', '{}');
INSERT INTO query (id, name, metadata) VALUES (1, 'Alice', '{"age":100}'), (2, 'Bob', '{}');
`
})

afterAll(async () => {
await client.raw`DROP TABLE users`
await client.raw`DROP TABLE query`

await client.quit()
})

describe('select', () => {
it('selects all columns', async () => {
const result = await new QueryBuilder(client, 'users').select().all()
const result = await new QueryBuilder(client, 'query').select().all()

expect(result).toEqual([
{
Expand All @@ -45,7 +45,7 @@ describe('QueryBuilder', () => {
})

it('selects specific columns', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.select('name')
.all()

Expand All @@ -55,15 +55,15 @@ describe('QueryBuilder', () => {

describe('where', () => {
it('column and value', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('name', 'Alice')
.pluck('id')

expect(result).toEqual([1])
})

it('column, operator, and value', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('name', '!=', 'Alice')
.pluck('id')

Expand All @@ -72,79 +72,79 @@ describe('QueryBuilder', () => {

describe('operator', () => {
it('IS NULL', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('name', 'IS NULL')
.pluck('id')

expect(result).toEqual([])
})

it('IS NOT NULL', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('name', 'IS NOT NULL')
.pluck('id')

expect(result).toEqual([1, 2])
})

it('IN', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('name', 'IN', ['Alice'])
.pluck('id')

expect(result).toEqual([1])
})

it('NOT IN', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('name', 'NOT IN', ['Alice'])
.pluck('id')

expect(result).toEqual([2])
})

it('>', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('id', '>', 1)
.pluck('id')

expect(result).toEqual([2])
})

it('>=', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('id', '>=', 1)
.pluck('id')

expect(result).toEqual([1, 2])
})

it('<', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('id', '<', 2)
.pluck('id')

expect(result).toEqual([1])
})

it('<=', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('id', '<=', 2)
.pluck('id')

expect(result).toEqual([1, 2])
})

it('!=', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('name', '!=', 'Alice')
.pluck('id')

expect(result).toEqual([2])
})

it('@>', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('metadata', '@>', { age: 100 })
.pluck('id')

Expand All @@ -153,15 +153,15 @@ describe('QueryBuilder', () => {

it('throws error for invalid operator', async () => {
await expect(() =>
new QueryBuilder(client, 'users')
new QueryBuilder(client, 'query')
.where('name', 'invalid' as any, 'Alice')
.pluck('id')
).toThrowError('Invalid operator: invalid')
})
})

it('multiple conditions', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.where('name', 'Alice')
.where('id', '>', 1)
.pluck('id')
Expand All @@ -172,7 +172,7 @@ describe('QueryBuilder', () => {

describe('limit', () => {
it('limits the number of results', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.limit(1)
.pluck('id')

Expand All @@ -182,7 +182,7 @@ describe('QueryBuilder', () => {

describe('offset', () => {
it('offsets the results', async () => {
const result = await new QueryBuilder(client, 'users')
const result = await new QueryBuilder(client, 'query')
.offset(1)
.pluck('id')

Expand All @@ -192,25 +192,51 @@ describe('QueryBuilder', () => {

describe('pluck', () => {
it('returns a single column', async () => {
const result = await new QueryBuilder(client, 'users').pluck('name')
const result = await new QueryBuilder(client, 'query').pluck('name')

expect(result).toEqual(['Alice', 'Bob'])
})
})

describe('count', () => {
it('counts the number of rows', async () => {
const result = await new QueryBuilder(client, 'users').count()
const result = await new QueryBuilder(client, 'query').count()

expect(result).toEqual(2)
})
})

describe('first', () => {
it('returns the first row', async () => {
const result = await new QueryBuilder(client, 'users').first()
const result = await new QueryBuilder(client, 'query').first()

expect(result).toEqual({ id: 1, name: 'Alice', metadata: { age: 100 } })
})
})

describe('orderBy', () => {
it('default order', async () => {
const result = await new QueryBuilder(client, 'query')
.orderBy('id')
.pluck('id')

expect(result).toEqual([1, 2])
})

it('ascending order', async () => {
const result = await new QueryBuilder(client, 'query')
.orderBy('id', 'ASC')
.pluck('id')

expect(result).toEqual([1, 2])
})

it('descending order', async () => {
const result = await new QueryBuilder(client, 'query')
.orderBy('id', 'DESC')
.pluck('id')

expect(result).toEqual([2, 1])
})
})
})
Loading

0 comments on commit 70cf01c

Please sign in to comment.