Skip to content

Commit

Permalink
fix(sql): serialize referenced types (#528)
Browse files Browse the repository at this point in the history
* test(orm-integration): one-to-one circular relation

* fix(sql): serialize referenced type

* rename test

* Update various.ts

Signed-off-by: Marcus S. Abildskov <8391194+marcus-sa@users.noreply.github.com>

* update

Signed-off-by: Marcus S. Abildskov <8391194+marcus-sa@users.noreply.github.com>

---------

Signed-off-by: Marcus S. Abildskov <8391194+marcus-sa@users.noreply.github.com>
  • Loading branch information
marcus-sa authored Jan 9, 2024
1 parent 9fca388 commit 2f68991
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
19 changes: 19 additions & 0 deletions packages/orm-integration/src/various.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,25 @@ import { randomBytes } from 'crypto';
Error.stackTraceLimit = 20;

export const variousTests = {
async testOneToOneCircularReferenceRelation(databaseFactory: DatabaseFactory) {
@entity.name('totocrr_inventory')
class Inventory {
id: number & PrimaryKey & AutoIncrement = 0;
constructor(public user: User & Reference) {}
}

@entity.name('totocrr_user')
class User {
id: number & PrimaryKey & AutoIncrement = 0;
inventory: Inventory & BackReference = new Inventory(this);
}

const database = await databaseFactory([Inventory, User]);

const user = cast<User>({});

await database.persist(user.inventory, user);
},
async testSkipDatabaseFieldForInserts(databaseFactory: DatabaseFactory) {
@entity.name('test_skip_database_field_insert')
class User {
Expand Down
30 changes: 17 additions & 13 deletions packages/sql/src/serializer/sql-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import {
ContainerAccessor,
executeTemplates,
executeTemplates, isBackReferenceType,
isReferenceType,
isUUIDType,
nodeBufferToArrayBuffer,
Expand All @@ -26,7 +26,7 @@ import {
TypeClass,
typedArrayToBuffer,
TypeObjectLiteral,
uuidAnnotation
uuidAnnotation,
} from '@deepkit/type';

export const hexTable: string[] = [];
Expand Down Expand Up @@ -96,8 +96,7 @@ function deserializeSqlArray(type: TypeArray, state: TemplateState) {
* For sql databases, objects will be serialised as JSON string.
*/
function serializeSqlObjectLiteral(type: TypeClass | TypeObjectLiteral, state: TemplateState) {
if (undefined !== referenceAnnotation.getFirst(type)) return;
if (!isDirectPropertyOfEntity(type)) return;
if (isReferenceType(type) || isBackReferenceType(type) || !isDirectPropertyOfEntity(type)) return;

//TypeClass|TypeObjectLiteral properties are serialized as JSON
state.setContext({ stringify: JSON.stringify });
Expand All @@ -117,6 +116,16 @@ function deserializeSqlObjectLiteral(type: TypeClass | TypeObjectLiteral, state:
serializeObjectLiteral(type, state);
}

function serializeReferencedType(type: Type, state: TemplateState) {
if (type.kind !== ReflectionKind.class && type.kind !== ReflectionKind.objectLiteral) return;
// state.setContext({ isObject, isReferenceType, isReferenceHydrated });
const reflection = ReflectionClass.from(type);
//the primary key is serialised for unhydrated references
state.template = `
${executeTemplates(state.fork(state.setter, new ContainerAccessor(state.accessor, JSON.stringify(reflection.getPrimary().getName()))), reflection.getPrimary().getType())}
`;
}

export class SqlSerializer extends Serializer {
name = 'sql';

Expand Down Expand Up @@ -182,15 +191,10 @@ export class SqlSerializer extends Serializer {
//for databases, types decorated with Reference will always only export the primary key.
const referenceType = referenceAnnotation.registerType({ kind: ReflectionKind.class, classType: Object, types: [] }, {});
this.serializeRegistry.removeDecorator(referenceType);
this.serializeRegistry.addDecorator(isReferenceType, (type, state) => {
if (type.kind !== ReflectionKind.class && type.kind !== ReflectionKind.objectLiteral) return;
// state.setContext({ isObject, isReferenceType, isReferenceHydrated });
const reflection = ReflectionClass.from(type);
//the primary key is serialised for unhydrated references
state.template = `
${executeTemplates(state.fork(state.setter, new ContainerAccessor(state.accessor, JSON.stringify(reflection.getPrimary().getName()))), reflection.getPrimary().getType())}
`;
});
this.serializeRegistry.addDecorator(isReferenceType, serializeReferencedType);

//for databases, types decorated with BackReference will always only export the primary key.
this.serializeRegistry.addDecorator(isBackReferenceType, serializeReferencedType);

this.serializeRegistry.registerBinary((type, state) => {
if (type.classType === ArrayBuffer) {
Expand Down

0 comments on commit 2f68991

Please sign in to comment.