@things-factory/kpi 10.1.37 → 10.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/pages/kpi-metric-value/kpi-metric-value-list-page.ts +5 -3
- package/client/pages/kpi-value/kpi-value-list-page.ts +5 -3
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +5 -3
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
- package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +1 -1
- package/dist-client/pages/kpi-value/kpi-value-list-page.js +5 -3
- package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/service/kpi/index.d.ts +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +4 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -1
- package/dist-server/service/kpi-value/index.d.ts +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/tests/list-search-db.test.ts +142 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/kpi",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.39",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "dist-client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@operato/app": "^10.0.0",
|
|
32
|
-
"@operato/data-grist": "^10.
|
|
32
|
+
"@operato/data-grist": "^10.19.0",
|
|
33
33
|
"@operato/dataset": "^10.0.0",
|
|
34
34
|
"@operato/ghost-print": "^10.0.0",
|
|
35
35
|
"@operato/graphql": "^10.0.0",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"@operato/shell": "^10.0.0",
|
|
42
42
|
"@operato/styles": "^10.0.0",
|
|
43
43
|
"@operato/utils": "^10.0.0",
|
|
44
|
-
"@things-factory/auth-base": "^10.1.
|
|
45
|
-
"@things-factory/dataset": "^10.1.
|
|
46
|
-
"@things-factory/shell": "^10.1.
|
|
44
|
+
"@things-factory/auth-base": "^10.1.39",
|
|
45
|
+
"@things-factory/dataset": "^10.1.39",
|
|
46
|
+
"@things-factory/shell": "^10.1.39"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "fe5257ad8995fe7e79275e287f36e95b5fd32d1c"
|
|
49
49
|
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two value lists answer the title bar search - against a real database.
|
|
3
|
+
*
|
|
4
|
+
* The screens send the term itself (`search-mode="term"`, ADR-0060 decision 10) and the door expands
|
|
5
|
+
* it over its own searchables. A pure test cannot see whether that list is one the entity can answer:
|
|
6
|
+
* a name the entity does not have throws, and a uuid column is an error on postgres (LOWER(uuid) has
|
|
7
|
+
* no function). kpiMetricValues had both - metricId and a group the entity never had - so the search
|
|
8
|
+
* would have answered with an error instead of rows.
|
|
9
|
+
*
|
|
10
|
+
* Postgres only, with TEST_POSTGRES_URL set - a throwaway container is enough, synchronize builds the
|
|
11
|
+
* tables:
|
|
12
|
+
*
|
|
13
|
+
* docker run -d --rm --name kpi-pg -e POSTGRES_PASSWORD=x -p 55433:5432 postgres:14-alpine
|
|
14
|
+
* TEST_POSTGRES_URL=postgres://postgres:x@localhost:55433/postgres yarn _test packages/kpi/tests
|
|
15
|
+
*
|
|
16
|
+
* Not sqlite, for two reasons: sqlite lowers a uuid without complaint, so it cannot show the defect;
|
|
17
|
+
* and it cannot build these tables at all - KpiMetric.collectType is declared type 'enum', which the
|
|
18
|
+
* sqlite driver rejects. Without the variable the suite is skipped, and says so.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { DataSource } from 'typeorm'
|
|
22
|
+
import { existsSync } from 'fs'
|
|
23
|
+
import { join } from 'path'
|
|
24
|
+
|
|
25
|
+
const POSTGRES = process.env.TEST_POSTGRES_URL
|
|
26
|
+
|
|
27
|
+
/* Entities pick their column types from ormconfig.type when they load (attachment's contents is blob
|
|
28
|
+
or bytea), so the driver is named before any of them is required. */
|
|
29
|
+
require('@things-factory/env').config.set('ormconfig', { type: 'postgres' })
|
|
30
|
+
|
|
31
|
+
const { DataSource: TypeOrmDataSource } = require('typeorm')
|
|
32
|
+
const shell = require('@things-factory/shell')
|
|
33
|
+
const authBase = require('@things-factory/auth-base')
|
|
34
|
+
/* KpiMetric points at dataset's DataSet, which points at integration's Scenario - the entity graph
|
|
35
|
+
has to close before the tables can be built (dataset's out-of-control reviews reach worklist). */
|
|
36
|
+
const integration = require('@things-factory/integration-base')
|
|
37
|
+
const worklist = require('@things-factory/worklist')
|
|
38
|
+
const dataset = require('@things-factory/dataset')
|
|
39
|
+
const attachment = require('@things-factory/attachment-base')
|
|
40
|
+
|
|
41
|
+
const DIST = join(__dirname, '..', 'dist-server')
|
|
42
|
+
if (!existsSync(join(DIST, 'service', 'index.js'))) {
|
|
43
|
+
throw new Error(`kpi's dist-server is missing - run "yarn workspace @things-factory/kpi build:server" first`)
|
|
44
|
+
}
|
|
45
|
+
/* The entities use type-graphql decorators that need tsc's metadata, which babel cannot give -
|
|
46
|
+
the same reason auth-base's DB tests load the compiled output (auth-base/tests/compiled.ts). */
|
|
47
|
+
const kpi = require(join(DIST, 'service', 'index.js'))
|
|
48
|
+
const { KpiValueQuery } = require(join(DIST, 'service', 'kpi-value', 'kpi-value-query.js'))
|
|
49
|
+
const { KpiMetricValueQuery } = require(join(DIST, 'service', 'kpi-metric-value', 'kpi-metric-value-query.js'))
|
|
50
|
+
|
|
51
|
+
let dataSource: DataSource
|
|
52
|
+
let domain: any
|
|
53
|
+
|
|
54
|
+
const onPostgres = POSTGRES ? describe : describe.skip
|
|
55
|
+
|
|
56
|
+
const context = () => ({ state: { domain } }) as any
|
|
57
|
+
const repo = (entity: any) => dataSource.getRepository(entity)
|
|
58
|
+
|
|
59
|
+
onPostgres('the value lists answer the title bar search (postgres, TEST_POSTGRES_URL)', () => {
|
|
60
|
+
beforeAll(async () => {
|
|
61
|
+
dataSource = new TypeOrmDataSource({
|
|
62
|
+
type: 'postgres',
|
|
63
|
+
url: POSTGRES,
|
|
64
|
+
synchronize: true,
|
|
65
|
+
dropSchema: true,
|
|
66
|
+
namingStrategy: new shell.NamingStrategy(),
|
|
67
|
+
entities: [
|
|
68
|
+
...shell.entities,
|
|
69
|
+
...authBase.entities,
|
|
70
|
+
...attachment.entities,
|
|
71
|
+
...integration.entities,
|
|
72
|
+
...worklist.entities,
|
|
73
|
+
...dataset.entities,
|
|
74
|
+
...kpi.entities
|
|
75
|
+
],
|
|
76
|
+
logging: false
|
|
77
|
+
})
|
|
78
|
+
await dataSource.initialize()
|
|
79
|
+
shell.addDataSource('default', dataSource)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
afterAll(async () => {
|
|
83
|
+
if (dataSource?.isInitialized) await dataSource.destroy()
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
beforeEach(async () => {
|
|
87
|
+
await dataSource.synchronize(true)
|
|
88
|
+
domain = await repo(shell.Domain).save({ name: 'Plant A', subdomain: 'plant-a' })
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('kpiValues', () => {
|
|
92
|
+
async function seed() {
|
|
93
|
+
const scrap = await repo(kpi.Kpi).save({ domain, name: 'Scrap rate' })
|
|
94
|
+
const oee = await repo(kpi.Kpi).save({ domain, name: 'OEE' })
|
|
95
|
+
await repo(kpi.KpiValue).save([
|
|
96
|
+
{ domain, kpi: scrap, version: 1, valueDate: '2026-09-01', value: 1.2, group: 'line-1' },
|
|
97
|
+
{ domain, kpi: oee, version: 1, valueDate: '2026-09-02', value: 81, group: 'line-2' }
|
|
98
|
+
])
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
it('finds a value by the name of its KPI', async () => {
|
|
102
|
+
await seed()
|
|
103
|
+
const { items, total } = await new KpiValueQuery().kpiValues({ search: 'scrap' }, context())
|
|
104
|
+
expect(total).toBe(1)
|
|
105
|
+
expect(items[0].valueDate).toBe('2026-09-01')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('finds a value by its group and by its date', async () => {
|
|
109
|
+
await seed()
|
|
110
|
+
expect((await new KpiValueQuery().kpiValues({ search: 'line-2' }, context())).total).toBe(1)
|
|
111
|
+
expect((await new KpiValueQuery().kpiValues({ search: '09-01' }, context())).total).toBe(1)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('answers the whole list without a term', async () => {
|
|
115
|
+
await seed()
|
|
116
|
+
expect((await new KpiValueQuery().kpiValues({}, context())).total).toBe(2)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
describe('kpiMetricValues', () => {
|
|
121
|
+
async function seed() {
|
|
122
|
+
const downtime = await repo(kpi.KpiMetric).save({ domain, name: 'Downtime minutes' })
|
|
123
|
+
const output = await repo(kpi.KpiMetric).save({ domain, name: 'Good units' })
|
|
124
|
+
await repo(kpi.KpiMetricValue).save([
|
|
125
|
+
{ domain, metric: downtime, valueDate: '2026-09-01', value: 42 },
|
|
126
|
+
{ domain, metric: output, valueDate: '2026-09-02', value: 900 }
|
|
127
|
+
])
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
it('finds a value by the name of its metric - an answer, not an error', async () => {
|
|
131
|
+
await seed()
|
|
132
|
+
const { items, total } = await new KpiMetricValueQuery().kpiMetricValues({ search: 'downtime' }, context())
|
|
133
|
+
expect(total).toBe(1)
|
|
134
|
+
expect(items[0].value).toBe(42)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('finds a value by its date', async () => {
|
|
138
|
+
await seed()
|
|
139
|
+
expect((await new KpiMetricValueQuery().kpiMetricValues({ search: '09-02' }, context())).total).toBe(1)
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
})
|