Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zibri",
"version": "2.1.2",
"version": "2.1.3",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"repository": {
Expand Down
39 changes: 16 additions & 23 deletions src/data-source/data-sources/postgres-data-source.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,35 +247,27 @@ export abstract class PostgresDataSource implements DataSourceInterface {
const inverseHasUpdate: boolean = this.hasCascadeFlag(inv.cascade, 'update');
const inverseHasInsert: boolean = this.hasCascadeFlag(inv.cascade, 'insert');

let onDelete: OnDeleteType | undefined;
let onUpdate: OnUpdateType | undefined;
let persistence: boolean = false;
if (thisHasRemove || inverseHasRemove) {
onDelete = 'CASCADE';
}
if (thisHasUpdate || inverseHasUpdate) {
onUpdate = 'CASCADE';
}
if (thisHasInsert || inverseHasInsert) {
persistence = true;
}
const onDelete: OnDeleteType | undefined = thisHasRemove || inverseHasRemove ? 'CASCADE' : undefined;
const onUpdate: OnUpdateType | undefined = thisHasUpdate || inverseHasUpdate ? 'CASCADE' : undefined;
const persistence: boolean = 'persistence' in metadata ? metadata.persistence : thisHasInsert || inverseHasInsert;
const nullable: boolean = typeof metadata.required === 'boolean' ? !metadata.required : true;

switch (metadata.type) {
case Relation.ONE_TO_ONE:
case Relation.ONE_TO_MANY:
case Relation.MANY_TO_MANY: {
return {
nullable: typeof metadata.required === 'boolean' ? !metadata.required : true,
nullable,
...metadata,
inverseSide: metadata.inverseSide as string,
onDelete,
onUpdate,
persistence: 'persistence' in metadata ? metadata.persistence : persistence
persistence
};
}
case Relation.MANY_TO_ONE: {
return {
nullable: typeof metadata.required === 'boolean' ? !metadata.required : true,
nullable,
joinColumn: true,
...metadata,
inverseSide: metadata.inverseSide as string,
Expand Down Expand Up @@ -303,18 +295,18 @@ export abstract class PostgresDataSource implements DataSourceInterface {
* @returns Typeorm column options.
* @throws When the metadata is incorrect.
*/
// eslint-disable-next-line sonar/cognitive-complexity
protected propertyToColumnOptions(
metadata: ExcludeStrict<PropertyMetadata, RelationMetadata<BaseEntity>>
): EntitySchemaColumnOptions {
const nullable: boolean = typeof metadata.required === 'boolean' ? !metadata.required : true;
switch (metadata.type) {
case 'file':
case 'boolean':
case 'object':
case 'unknown':
case 'date': {
return {
nullable: typeof metadata.required === 'boolean' ? !metadata.required : true,
nullable,
...metadata,
type: this.columnTypeMapping[metadata.type],
default: undefined
Expand All @@ -323,14 +315,14 @@ export abstract class PostgresDataSource implements DataSourceInterface {
case 'array': {
if (metadata.items.type === 'object') {
return {
nullable: typeof metadata.required === 'boolean' ? !metadata.required : true,
nullable,
...metadata,
type: this.columnTypeMapping[metadata.items.type],
default: undefined
};
}
return {
nullable: typeof metadata.required === 'boolean' ? !metadata.required : true,
nullable,
...metadata,
type: this.columnTypeMapping[metadata.items.type],
array: true,
Expand All @@ -339,21 +331,22 @@ export abstract class PostgresDataSource implements DataSourceInterface {
}
case 'number': {
return {
nullable: typeof metadata.required === 'boolean' ? !metadata.required : true,
nullable,
generated: metadata.primary ? 'increment' : undefined,
...metadata,
type: this.columnTypeMapping[metadata.type],
default: undefined,
transformer: {
// eslint-disable-next-line unicorn/no-null
to: (v: number | null) => v ? String(v) : null,
from: (v: string | null) => v ? Number(v) : undefined
to: (v: number | null) => v != null ? String(v) : null,
// eslint-disable-next-line unicorn/no-null
from: (v: string | null) => v != null ? Number(v) : undefined
}
};
}
case 'string': {
return {
nullable: typeof metadata.required === 'boolean' ? !metadata.required : true,
nullable,
generated: metadata.primary ? 'uuid' : undefined,
...metadata,
type: metadata.format === 'uuid' || metadata.primary ? 'uuid' : this.columnTypeMapping[metadata.type],
Expand Down
82 changes: 82 additions & 0 deletions src/data-source/repository.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { beforeAll, afterAll, describe, it, expect } from '@jest/globals';
import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';

import { DataSource } from './decorators';
import { inject } from '../di';
import { PostgresDataSource, PostgresOptions } from './data-sources';
import { MigrationEntity } from './migration';
import { POSTGRES_TEST_IMAGE } from '../__testing__';
import { BaseEntity } from '../entity/base-entity.model';
import { Newable, OmitStrict } from '../types';
import { Repository } from './repository';
import { Entity, Property } from '../entity';

@Entity()
class VisitStats extends BaseEntity {
@Property.number()
count!: number;

@Property.number()
countFirstVisit!: number;

@Property.string()
targetSite!: string;

@Property.string({ required: false })
referrer: string | undefined;

@Property.string()
domain!: string;

@Property.date()
date!: Date;
}

@DataSource()
class TestDataSource extends PostgresDataSource {
options: PostgresOptions = {
host: 'localhost',
username: 'postgres',
password: 'password',
database: 'db',
synchronize: true
};
entities: Newable<BaseEntity>[] = [MigrationEntity, VisitStats];
}

describe('repository', () => {
let container: StartedPostgreSqlContainer;
let ds: TestDataSource;

beforeAll(async () => {
container = await new PostgreSqlContainer(POSTGRES_TEST_IMAGE)
.withDatabase('db')
.withUsername('postgres')
.withPassword('password')
.start();
ds = inject(TestDataSource);
ds.options = {
...ds.options,
port: container.getMappedPort(5432)
};
await ds.init();
}, 20000);

afterAll(async () => {
await container.stop();
});

it('create', async () => {
const repo: Repository<VisitStats> = ds.getRepository(VisitStats);
const visitStats: OmitStrict<VisitStats, 'id'> = {
count: 1,
countFirstVisit: 0,
targetSite: '/test',
referrer: 'google.de',
date: new Date(),
domain: 'localhost'
};
await repo.create(visitStats);
expect((await repo.findAll()).length).toBe(1);
});
});
10 changes: 6 additions & 4 deletions src/validation/validation.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,11 @@ export class ValidationService implements ValidationServiceInterface {
}
const fullKey: string = parentKey ? `${parentKey}.${key}` : key;

if (property == undefined && (typeof metadata.required === 'boolean' ? metadata.required : metadata.required(entity))) {
const required: boolean = typeof metadata.required === 'boolean' ? metadata.required : metadata.required(entity);
if (property == undefined && required) {
return [new IsRequiredValidationProblem(fullKey)];
}
if (property == undefined && !(typeof metadata.required === 'boolean' ? metadata.required : metadata.required(entity))) {
if (property == undefined && !required) {
return [];
}
if (!Array.isArray(property)) {
Expand Down Expand Up @@ -271,10 +272,11 @@ export class ValidationService implements ValidationServiceInterface {
}
const fullKey: string = parentKey ? `${parentKey}.${key}` : key;

if (property == undefined && (typeof metadata.required === 'boolean' ? metadata.required : metadata.required(entity))) {
const required: boolean = typeof metadata.required === 'boolean' ? metadata.required : metadata.required(entity);
if (property == undefined && required) {
return [new IsRequiredValidationProblem(fullKey)];
}
if (property == undefined && !(typeof metadata.required === 'boolean' ? metadata.required : metadata.required(entity))) {
if (property == undefined && !required) {
return [];
}
if (typeof property !== 'object') {
Expand Down
Loading