-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0c1050c
commit a11a631
Showing
6 changed files
with
139 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { test, expect, beforeAll } from 'vitest'; | ||
import { Database, database } from '@do-ob/data/database'; | ||
import { seed } from '@do-ob/data/seed'; | ||
import { schema } from '@do-ob/data/schema'; | ||
import { prepareInput } from '@/test/utility'; | ||
import { remove } from './remove'; | ||
|
||
let db: Database; | ||
|
||
beforeAll(async () => { | ||
db = await seed(database()); | ||
}); | ||
|
||
test('remove an entity', async () => { | ||
const input = await prepareInput(db); | ||
const result = await db.transaction( | ||
remove(input, schema.entity, '00000000-0000-0000-0000-000000000000'), | ||
); | ||
|
||
expect(result).toEqual([ | ||
{ | ||
$id: '00000000-0000-0000-0000-000000000000', | ||
}, | ||
]); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import type { Transaction } from './transaction.types'; | ||
import { and, eq, SQL, sql, type TableConfig } from 'drizzle-orm'; | ||
import type { PgTableWithColumns } from 'drizzle-orm/pg-core'; | ||
import { schema } from '@do-ob/data/schema'; | ||
import { auditMutation } from './audit'; | ||
import { Ambit, type Input } from '@do-ob/core'; | ||
import { RowList } from 'postgres'; | ||
|
||
/** | ||
* Builds an sql filter based on an ambit. | ||
*/ | ||
function scope( | ||
$subject: string, | ||
ambit: Ambit, | ||
): SQL { | ||
switch(ambit) { | ||
case Ambit.Global: | ||
return sql`true`; | ||
case Ambit.Owned: | ||
return eq(schema.entity.$owner, $subject); | ||
case Ambit.Created: | ||
return eq(schema.entity.$creator, $subject); | ||
case Ambit.Member: | ||
return sql`false`; // TODO: Implement member scope. | ||
case Ambit.None: | ||
default: | ||
return sql`false`; | ||
} | ||
} | ||
|
||
export function remove< | ||
C extends TableConfig, | ||
> ( | ||
input: Input, | ||
table: PgTableWithColumns<C>, | ||
$id: string, | ||
) { | ||
return async (tx: Transaction): Promise<[PgTableWithColumns<C>['$inferSelect']]> => { | ||
const { ambit, $subject, $dispatch } = input; | ||
|
||
if (!$subject) { | ||
throw new Error('Unauthorized. No subject provided for the update operation.'); | ||
} | ||
|
||
/** | ||
* Drizzle ORM does not have the `from` clause for the update builder... | ||
* so we have to build the SQL until then. | ||
* | ||
* See issue for updates: https://github.com/drizzle-team/drizzle-orm/issues/2304 | ||
*/ | ||
const chunks: SQL[] = []; | ||
chunks.push(tx.update(schema.entity).set({ deleted: true }).getSQL()); | ||
chunks.push(sql`where ${and( | ||
eq(schema.entity.$id, $id), | ||
scope($subject, ambit), | ||
)}`); | ||
chunks.push(sql`returning *`); | ||
const removeSql = sql.join(chunks, sql.raw(' ')); | ||
|
||
const { rows } = (await tx.execute(removeSql)) as unknown as { rows: RowList<object[]> }; | ||
|
||
/** | ||
* Rollback if the update failed or it updated more than one record somehow. | ||
*/ | ||
if(rows.length === 0 || rows.length > 1) { | ||
tx.rollback(); | ||
} | ||
|
||
/** | ||
* Remove this select statement once the `from` method is available in drizzle-orm. | ||
*/ | ||
const [ result ] = await tx.select().from(table).where(eq(table.$id, $id)) as [PgTableWithColumns<C>['$inferSelect'] & { $id: string }]; | ||
|
||
/** | ||
* Rollback if the updated record failed to return anything. | ||
*/ | ||
if(!result) { | ||
tx.rollback(); | ||
} | ||
|
||
if ($dispatch) { | ||
await tx.transaction(auditMutation($dispatch, [ | ||
{ | ||
type: 'remove', | ||
table, | ||
value: result, | ||
}, | ||
])); | ||
} | ||
|
||
return [ | ||
result, | ||
]; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters