Skip to content

Commit d66ccc7

Browse files
committed
Implementado .hasMany() para mapear lista de objetos que desejam armazenar apenas a referencia unica para a outra tabela.
1 parent 4336300 commit d66ccc7

6 files changed

Lines changed: 231 additions & 7 deletions

File tree

src/crud/query/query.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,17 @@ export class Query<T> extends SqlBase<T> {
321321
Promise.all(promises)
322322
.then(result => {
323323
result.forEach(r => {
324-
ModelUtils.set(model, r.field, r.value);
324+
const fieldArraySplit = r.field.split("[?].");
325+
if (fieldArraySplit.length === 1) {
326+
ModelUtils.set(model, fieldArraySplit[0], r.value);
327+
} else {
328+
const values = (r.value as any[]).map(value => {
329+
const item = {};
330+
ModelUtils.set(item, fieldArraySplit[1], value);
331+
return item;
332+
});
333+
ModelUtils.set(model, fieldArraySplit[0], values);
334+
}
325335
});
326336
resolve(model);
327337
})

src/crud/sql-base.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Utils } from "../core/utils";
66
import { SqlCompilable } from "./sql-compilable";
77
import { QueryCompiled } from "../core/query-compiled";
88
import { SqlExecutable } from "./sql-executable";
9+
import { ModelUtils } from "../core/model-utils";
910

1011
export abstract class SqlBase<T> implements SqlCompilable, SqlExecutable {
1112

@@ -45,9 +46,11 @@ export abstract class SqlBase<T> implements SqlCompilable, SqlExecutable {
4546
protected compileDependencyByValue(dependency: MapperTable): QueryCompiled[] {
4647
const script: QueryCompiled[] = [];
4748
const columnDependency = this.mapperTable.columns.find(x => x.tableReference === dependency.tableName);
48-
const valuesDependency: any[] = Utils.getValue(this.model(), columnDependency.fieldReference);
49+
const fieldArraySplit = columnDependency.fieldReference.split("[?].");
50+
const valuesDependency: any[] = Utils.getValue(this.model(), fieldArraySplit[0]);
4951
valuesDependency.forEach((value, index) => {
50-
this.checkAndPush(script, this.resolveDependencyByValue(dependency, value, index));
52+
const valueItem = fieldArraySplit.length > 1 ? ModelUtils.get(value, fieldArraySplit[1]) : value;
53+
this.checkAndPush(script, this.resolveDependencyByValue(dependency, valueItem, index));
5154
});
5255
return script;
5356
}

src/metadata-table.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,18 @@ export class MetadataTable<T> {
5050
type: new () => TArray,
5151
tableName: string,
5252
): MetadataTable<T> {
53-
const column = this.columnName(expression);
53+
let mapperColumn: MapperColumn = {
54+
column: this.columnName(expression),
55+
fieldType: this._databaseHelper.getFieldType(type)
56+
} as MapperColumn;
57+
const instanceMapper = this.validInstanceMapper(type ? new type() : expression(this.instance), mapperColumn.column);
58+
if (!this._databaseHelper.isTypeSimpleByType(mapperColumn.fieldType)) {
59+
// if (!this._databaseHelper.isTypeSimple(instanceMapper as any)) {
60+
mapperColumn = this.getMapperColumnReference(instanceMapper, `${mapperColumn.column}[?]`);
61+
}
5462
this.addDependency(
55-
column,
56-
FieldType.ARRAY | this._databaseHelper.getFieldType(type),
63+
mapperColumn.column,
64+
FieldType.ARRAY | mapperColumn.fieldType,
5765
tableName
5866
);
5967
return this;
@@ -132,6 +140,7 @@ export class MetadataTable<T> {
132140
}
133141

134142
private validInstanceMapper<TType>(instance: TType, propertyMapperForMessage: string): TType {
143+
console.log(instance);
135144
if (instance === void 0) {
136145
throw new DatabaseBuilderError(`Mapper: ${this.newable.name}, can not get instance of mapped property ('${propertyMapperForMessage}')`);
137146
}

src/test/mappers-table-new.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ export class MappersTableNew extends MapperBase {
8989
this.autoMapper(Imagem, x => x.internalKey, PrimaryKeyType.Assigned);
9090
this.autoMapper(Linha, x => x.codeImport, PrimaryKeyType.Assigned);
9191
this.autoMapper(Referencia, x => x.codeImport, PrimaryKeyType.Assigned)
92-
// .hasMany(x => x.referenciasRelacionadas, Referencia, "ReferenciasRelacionadas")
92+
.hasMany(x => x.referenciasRelacionadas, Referencia, "ReferenciasRelacionadas")
93+
// .hasOne()
9394
;
9495
this.autoMapper(Estrutura, x => x.codeImport, PrimaryKeyType.Assigned);
9596
}

src/test/objeto-to-test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { Cliente } from "./models/cliente";
1414
import * as moment from "moment";
1515
import { ContasReceber } from "./models/contas-receber";
1616
import { HeaderSimple } from "./models/header-simple";
17+
import { Referencia } from "./models/referencia";
18+
import { Imagem } from "./models/imagem";
1719

1820
export class ObjectToTest {
1921

@@ -116,4 +118,29 @@ export class ObjectToTest {
116118
descricao: "Header Test",
117119
items: ["abc", "def", "ghi"]
118120
} as HeaderSimple;
121+
122+
public static referencia = {
123+
codeImport: 20,
124+
codigo: "abcCode",
125+
descricao: "Referencia Test",
126+
restricaoGrade: ["31", "32", "33", "34", "35"],
127+
referenciasRelacionadas: [
128+
{
129+
codeImport: 21
130+
} as Referencia,
131+
{
132+
codeImport: 23
133+
} as Referencia,
134+
{
135+
codeImport: 25
136+
} as Referencia,
137+
{
138+
codeImport: 27
139+
} as Referencia,
140+
],
141+
imagem: {
142+
internalKey: 30
143+
} as Imagem,
144+
deleted: false
145+
} as Referencia;
119146
}

src/test/sqlite.spec.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { Crud } from "../crud";
99
import { GuidClazz } from "./models/guid-clazz";
1010
import { Uf } from "./models/uf";
1111
import { HeaderSimple } from "./models/header-simple";
12+
import { Referencia } from "./models/referencia";
13+
import { Imagem } from "./models/imagem";
1214

1315
describe("SQLite", async () => {
1416
const mapper = getMapper();
@@ -313,4 +315,176 @@ describe("SQLite", async () => {
313315
const dropResult = await ddl.drop(HeaderSimple).execute(false);
314316
expect(dropResult.length).to.equal(1);
315317
});
318+
319+
it("Referencia cascade (property compost)", async () => {
320+
321+
ddl.enableLog = true;
322+
const createResult = await ddl.create(Referencia).execute();
323+
expect(createResult.length).to.equal(2);
324+
325+
crud.enableLog = true;
326+
const insertResult1 = await crud.insert(Referencia, ObjectToTest.referencia).execute();
327+
expect(insertResult1.length).to.equal(ObjectToTest.referencia.referenciasRelacionadas.length + 1);
328+
expect(insertResult1[0].rowsAffected).to.equal(1);
329+
ObjectToTest.referencia.referenciasRelacionadas.forEach((value, index) => {
330+
expect(insertResult1[index + 1].rowsAffected).to.equal(1);
331+
});
332+
333+
const referencia2 = {
334+
codeImport: 200,
335+
codigo: "fffff",
336+
descricao: "Referencia 2",
337+
restricaoGrade: ["41", "42", "43", "44", "45"],
338+
referenciasRelacionadas: [
339+
{
340+
codeImport: 201
341+
} as Referencia,
342+
{
343+
codeImport: 203
344+
} as Referencia,
345+
{
346+
codeImport: 205
347+
} as Referencia,
348+
{
349+
codeImport: 207
350+
} as Referencia,
351+
],
352+
imagem: {
353+
internalKey: 40
354+
} as Imagem,
355+
deleted: false
356+
} as Referencia;
357+
358+
const insertResult2 = await crud.insert(Referencia, referencia2).execute();
359+
expect(insertResult2.length).to.equal(referencia2.referenciasRelacionadas.length + 1);
360+
expect(insertResult2[0].rowsAffected).to.equal(1);
361+
referencia2.referenciasRelacionadas.forEach((value, index) => {
362+
expect(insertResult2[index + 1].rowsAffected).to.equal(1);
363+
});
364+
365+
const referencia3 = {
366+
codeImport: 300,
367+
codigo: "aaaaaa",
368+
descricao: "Referencia 3",
369+
restricaoGrade: ["21", "22", "23", "24", "25"],
370+
referenciasRelacionadas: [
371+
{
372+
codeImport: 301
373+
} as Referencia,
374+
{
375+
codeImport: 303
376+
} as Referencia,
377+
{
378+
codeImport: 305
379+
} as Referencia,
380+
{
381+
codeImport: 307
382+
} as Referencia,
383+
],
384+
imagem: {
385+
internalKey: 50
386+
} as Imagem,
387+
deleted: false
388+
} as Referencia;
389+
390+
const insertResult3 = await crud.insert(Referencia, referencia3).execute();
391+
expect(insertResult3.length).to.equal(referencia3.referenciasRelacionadas.length + 1);
392+
expect(insertResult3[0].rowsAffected).to.equal(1);
393+
referencia3.referenciasRelacionadas.forEach((value, index) => {
394+
expect(insertResult3[index + 1].rowsAffected).to.equal(1);
395+
});
396+
397+
const selectResult = await crud.query(Referencia).toList();
398+
expect(selectResult.length).to.equal(3);
399+
400+
expect(selectResult[0].referenciasRelacionadas.length).to.equal(ObjectToTest.referencia.referenciasRelacionadas.length);
401+
expect(selectResult[0].codeImport).to.equal(ObjectToTest.referencia.codeImport);
402+
expect(selectResult[0].descricao).to.equal(ObjectToTest.referencia.descricao);
403+
ObjectToTest.referencia.referenciasRelacionadas.forEach((value, index) => {
404+
expect(selectResult[0].referenciasRelacionadas[index].codeImport).to.equal(value.codeImport);
405+
});
406+
407+
expect(selectResult[1].referenciasRelacionadas.length).to.equal(referencia2.referenciasRelacionadas.length);
408+
expect(selectResult[1].codeImport).to.equal(referencia2.codeImport);
409+
expect(selectResult[1].descricao).to.equal(referencia2.descricao);
410+
referencia2.referenciasRelacionadas.forEach((value, index) => {
411+
expect(selectResult[1].referenciasRelacionadas[index].codeImport).to.equal(value.codeImport);
412+
});
413+
414+
expect(selectResult[2].referenciasRelacionadas.length).to.equal(referencia3.referenciasRelacionadas.length);
415+
expect(selectResult[2].codeImport).to.equal(referencia3.codeImport);
416+
expect(selectResult[2].descricao).to.equal(referencia3.descricao);
417+
referencia3.referenciasRelacionadas.forEach((value, index) => {
418+
expect(selectResult[2].referenciasRelacionadas[index].codeImport).to.equal(value.codeImport);
419+
});
420+
421+
referencia2.descricao = "Editado";
422+
const oldCountItems = referencia2.referenciasRelacionadas.length;
423+
referencia2.referenciasRelacionadas.splice(referencia2.referenciasRelacionadas.length - 1, 1);
424+
referencia2.referenciasRelacionadas = [...referencia2.referenciasRelacionadas, {
425+
codeImport: 222
426+
} as Referencia];
427+
428+
const updateResult = await crud.update(Referencia, referencia2)
429+
.where(where => {
430+
where.equal(x => x.codeImport, referencia2.codeImport);
431+
})
432+
.execute();
433+
const countUpdateResultExtraItems = 2; /* Update (Main) e Delete (Items) */
434+
expect(updateResult.length).to.equal(referencia2.referenciasRelacionadas.length + countUpdateResultExtraItems);
435+
/* Update (Main) */
436+
expect(updateResult[0].rowsAffected).to.equal(1);
437+
/* Delete (Items) */
438+
expect(updateResult[1].rowsAffected).to.equal(oldCountItems);
439+
referencia2.referenciasRelacionadas.forEach((value, index) => {
440+
expect(updateResult[index + countUpdateResultExtraItems].rowsAffected).to.equal(1);
441+
});
442+
443+
const selectUpdateResult = await crud.query(Referencia)
444+
.where(where => {
445+
where.equal(x => x.codeImport, referencia2.codeImport);
446+
})
447+
.firstOrDefault();
448+
expect(selectUpdateResult.referenciasRelacionadas.length).to.equal(referencia2.referenciasRelacionadas.length);
449+
expect(selectUpdateResult.codeImport).to.equal(referencia2.codeImport);
450+
expect(selectUpdateResult.descricao).to.equal(referencia2.descricao);
451+
referencia2.referenciasRelacionadas.forEach((value, index) => {
452+
expect(selectUpdateResult.referenciasRelacionadas[index].codeImport).to.equal(value.codeImport);
453+
});
454+
455+
const deleteResult1 = await crud.delete(Referencia, referencia2)
456+
.execute();
457+
expect(deleteResult1.length).to.equal(2);
458+
/* Main deleted */
459+
expect(deleteResult1[0].rowsAffected).to.equal(1);
460+
/* Itens deleted */
461+
expect(deleteResult1[1].rowsAffected).to.equal(referencia2.referenciasRelacionadas.length);
462+
463+
const deleteResult2 = await crud.deleteByKey(Referencia, ObjectToTest.referencia.codeImport)
464+
.execute();
465+
expect(deleteResult2.length).to.equal(2);
466+
/* Main deleted */
467+
expect(deleteResult2[0].rowsAffected).to.equal(1);
468+
/* Itens deleted */
469+
expect(deleteResult2[1].rowsAffected).to.equal(ObjectToTest.referencia.referenciasRelacionadas.length);
470+
471+
const selectResult2 = await crud.query(Referencia).toList();
472+
expect(selectResult2.length).to.equal(1);
473+
expect(selectResult2[0].referenciasRelacionadas.length).to.equal(referencia3.referenciasRelacionadas.length);
474+
expect(selectResult2[0].codeImport).to.equal(referencia3.codeImport);
475+
expect(selectResult2[0].descricao).to.equal(referencia3.descricao);
476+
referencia3.referenciasRelacionadas.forEach((value, index) => {
477+
expect(selectResult2[0].referenciasRelacionadas[index].codeImport).to.equal(value.codeImport);
478+
});
479+
480+
/* Test select not cascade with data in itens */
481+
const selectResultNotCascade = await crud.query(Referencia).toList(false);
482+
expect(selectResultNotCascade.length).to.equal(1);
483+
expect(selectResultNotCascade[0].referenciasRelacionadas.length).to.equal(0);
484+
expect(selectResultNotCascade[0].codeImport).to.equal(referencia3.codeImport);
485+
expect(selectResultNotCascade[0].descricao).to.equal(referencia3.descricao);
486+
487+
const dropResult = await ddl.drop(Referencia).execute();
488+
expect(dropResult.length).to.equal(2);
489+
});
316490
});

0 commit comments

Comments
 (0)