Knexify queries.

Add additional test cases for cases where multiple entities are inserted.

Signed-off-by: Jussi Hallila <jussi@hallila.com>
This commit is contained in:
Jussi Hallila
2022-01-14 13:20:35 +01:00
parent cd8bf7a4ab
commit 87f37b1674
2 changed files with 185 additions and 11 deletions
@@ -310,6 +310,81 @@ describe('Tech Insights database', () => {
});
});
it('should delete extraneous rows for each entity when MaxItems is defined. Should leave only n latest', async () => {
const deviledFact = (it: {}) => ({
...it,
facts: JSON.stringify({
testNumberFact: 666,
}),
});
await testDbClient.batchInsert('facts', additionalFacts.map(deviledFact));
const preInsertionFacts = await testDbClient('facts').select();
expect(preInsertionFacts).toHaveLength(3);
await testDbClient.batchInsert(
'facts',
preInsertionFacts.map(it => ({ ...it, entity: 'b:b/b' })),
);
const timestamp = DateTime.now().plus(Duration.fromMillis(1111));
const factsToBeInserted = [
{
timestamp: timestamp,
entity: {
namespace: 'a',
kind: 'a',
name: 'a',
},
facts: {
testNumberFact: 555,
},
},
{
timestamp: timestamp,
entity: {
namespace: 'b',
kind: 'b',
name: 'b',
},
facts: {
testNumberFact: 555,
},
},
];
const maxItems = 2;
await store.insertFacts({
id: 'test-fact',
facts: factsToBeInserted,
lifecycle: { maxItems },
});
const afterInsertionFacts = await testDbClient('facts').select();
const inserted = {
id: 'test-fact',
version: '0.0.1-test',
timestamp: timestamp.toISO(),
entity: 'a:a/a',
facts: JSON.stringify({ testNumberFact: 555 }),
};
expect(afterInsertionFacts).toHaveLength(maxItems * 2);
expect(afterInsertionFacts[0]).toMatchObject(
deviledFact(additionalFacts[0]),
);
expect(afterInsertionFacts[1]).toMatchObject({
...deviledFact(additionalFacts[0]),
entity: 'b:b/b',
});
expect(afterInsertionFacts[2]).toMatchObject(inserted);
expect(afterInsertionFacts[3]).toMatchObject({
...inserted,
entity: 'b:b/b',
});
});
it('should delete extraneous rows when TTL is defined. Should leave only items with timestamp greater than TTL', async () => {
const oldStaledOutFact = (it: {}) => ({
...it,
@@ -362,4 +437,95 @@ describe('Tech Insights database', () => {
oldStaledOutFact(additionalFacts[0]),
);
});
it('should delete extraneous rows for each entity when TTL expired', async () => {
const oldStaledOutFact = (it: {}) => ({
...it,
facts: JSON.stringify({
testNumberFact: 666,
}),
timestamp: DateTime.now().minus({ weeks: 3 }).toISO(),
});
await testDbClient.batchInsert(
'facts',
additionalFacts.map(oldStaledOutFact),
);
const preInsertionFacts = await testDbClient('facts').select();
expect(preInsertionFacts).toHaveLength(3);
await testDbClient.batchInsert(
'facts',
preInsertionFacts.map(it => ({ ...it, entity: 'b:b/b' })),
);
const timestamp = DateTime.now().plus(Duration.fromMillis(1111));
const factsToBeInserted = [
{
timestamp: timestamp,
entity: {
namespace: 'a',
kind: 'a',
name: 'a',
},
facts: {
testNumberFact: 555,
},
},
{
timestamp: timestamp,
entity: {
namespace: 'b',
kind: 'b',
name: 'b',
},
facts: {
testNumberFact: 555,
},
},
];
await store.insertFacts({
id: 'test-fact',
facts: factsToBeInserted,
lifecycle: { timeToLive: { weeks: 2 } },
});
const afterInsertionFacts = await testDbClient('facts')
.select()
.orderBy('timestamp', 'desc');
expect(afterInsertionFacts).toHaveLength(6);
expect(afterInsertionFacts[0]).toMatchObject({
id: 'test-fact',
version: '0.0.1-test',
timestamp: timestamp.toISO(),
entity: 'a:a/a',
facts: JSON.stringify({ testNumberFact: 555 }),
});
expect(afterInsertionFacts[1]).toMatchObject({
id: 'test-fact',
version: '0.0.1-test',
timestamp: timestamp.toISO(),
entity: 'b:b/b',
facts: JSON.stringify({ testNumberFact: 555 }),
});
expect(afterInsertionFacts[2]).toMatchObject(facts[1]);
expect(afterInsertionFacts[3]).toMatchObject({
...facts[1],
entity: 'b:b/b',
});
expect(afterInsertionFacts[4]).toMatchObject(facts[0]);
expect(afterInsertionFacts[5]).toMatchObject({
...facts[0],
entity: 'b:b/b',
});
expect(afterInsertionFacts).not.toContainEqual(
oldStaledOutFact(additionalFacts[0]),
);
expect(afterInsertionFacts).not.toContainEqual({
...oldStaledOutFact(additionalFacts[0]),
entity: 'b:b/b',
});
});
});
@@ -215,16 +215,25 @@ export class TechInsightsDatabase implements TechInsightsStore {
factRows.map(it => [it.id, it.entity]),
)
.and.leftJoin(
this.db.raw(
`(select *
from (select id fid,
entity fentity,
timestamp ftimestamp,
row_number() over (partition by id, entity order by timestamp desc) as fact_rank
from facts) ranks
where fact_rank <= ?? ) as filterjoin`,
maxItems,
),
joinTable =>
joinTable
.select('*')
.from(
this.db('facts')
.column(
{ fid: 'id' },
{ fentity: 'entity' },
{ ftimestamp: 'timestamp' },
)
.column(
this.db.raw(
'row_number() over (partition by id, entity order by timestamp desc) as fact_rank',
),
)
.as('ranks'),
)
.where('fact_rank', '<=', maxItems)
.as('filterjoin'),
joinClause => {
joinClause
.on('filterjoin.fid', 'facts.id')
@@ -233,7 +242,6 @@ export class TechInsightsDatabase implements TechInsightsStore {
},
)
.whereNull('filterjoin.fid');
await tx('facts')
.whereIn(
['id', 'entity', 'timestamp'],