@things-factory/shell 10.0.0-zeta.8 → 10.0.0

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.
Files changed (43) hide show
  1. package/client/entries/public/home.js +1 -1
  2. package/client/themes/app-theme.css +8 -24
  3. package/client/themes/calendar-theme.css +0 -7
  4. package/client/themes/grist-theme.css +13 -37
  5. package/client/themes/layout-theme.css +3 -23
  6. package/client/themes/report-theme.css +0 -9
  7. package/client/themes/theme-base.css +30 -0
  8. package/client/themes/tooltip-theme.css +0 -4
  9. package/dist-server/bootstrap-hooks.d.ts +51 -0
  10. package/dist-server/bootstrap-hooks.js +39 -0
  11. package/dist-server/bootstrap-hooks.js.map +1 -0
  12. package/dist-server/index.d.ts +1 -0
  13. package/dist-server/index.js +1 -0
  14. package/dist-server/index.js.map +1 -1
  15. package/dist-server/initializers/database.js +4 -1
  16. package/dist-server/initializers/database.js.map +1 -1
  17. package/dist-server/server-dev.js +13 -10
  18. package/dist-server/server-dev.js.map +1 -1
  19. package/dist-server/server.js +12 -8
  20. package/dist-server/server.js.map +1 -1
  21. package/dist-server/service/domain/domain-mutation.js +3 -2
  22. package/dist-server/service/domain/domain-mutation.js.map +1 -1
  23. package/dist-server/tsconfig.tsbuildinfo +1 -1
  24. package/dist-server/typeorm/get-data-encryption-key.js +11 -1
  25. package/dist-server/typeorm/get-data-encryption-key.js.map +1 -1
  26. package/dist-server/utils/apply-domain-filter.d.ts +17 -0
  27. package/dist-server/utils/apply-domain-filter.js +30 -0
  28. package/dist-server/utils/apply-domain-filter.js.map +1 -0
  29. package/dist-server/utils/condition-builder.js +15 -7
  30. package/dist-server/utils/condition-builder.js.map +1 -1
  31. package/dist-server/utils/get-query-builder-from-list-params.d.ts +39 -9
  32. package/dist-server/utils/get-query-builder-from-list-params.js +83 -40
  33. package/dist-server/utils/get-query-builder-from-list-params.js.map +1 -1
  34. package/dist-server/utils/list-params-converter.js +8 -6
  35. package/dist-server/utils/list-params-converter.js.map +1 -1
  36. package/dist-server/utils/list-query-builder.js +2 -14
  37. package/dist-server/utils/list-query-builder.js.map +1 -1
  38. package/jest.config.js +5 -0
  39. package/package.json +12 -12
  40. package/tests/get-query-builder-features.test.ts +229 -0
  41. package/tests/list-param-operators.test.ts +87 -0
  42. package/tests/manifest-contract.test.ts +38 -0
  43. package/client/store.ts +0 -15
@@ -0,0 +1,87 @@
1
+ import 'reflect-metadata'
2
+ import { Column, DataSource, Entity, PrimaryColumn, Repository } from 'typeorm'
3
+
4
+ import { getQueryBuilderFromListParams } from '../server/utils/get-query-builder-from-list-params.js'
5
+ import { ListParam } from '../server/service/common-types/list-param.js'
6
+
7
+ /**
8
+ * 목록 필터 연산자의 SQL 이식성 회귀 테스트.
9
+ *
10
+ * 배경: 과거 boolean 연산자가 `IS TRUE/FALSE`(MSSQL/Oracle 미지원), 그리고
11
+ * `IS PRESENT/BLANK/EMPTY NUMERIC ID`(어떤 DB 에서도 무효) 를 raw SQL 로 방출했다.
12
+ * 파라미터 바인딩 기반의 이식성 SQL 로 교체한 뒤, SQLite 에서 실제 실행 결과를 고정한다.
13
+ */
14
+
15
+ @Entity()
16
+ class Widget {
17
+ @PrimaryColumn({ type: 'integer' })
18
+ id!: number
19
+
20
+ @Column({ type: 'boolean', nullable: true })
21
+ flag!: boolean | null
22
+
23
+ @Column({ type: 'text', nullable: true })
24
+ title!: string | null
25
+
26
+ @Column({ type: 'integer', nullable: true })
27
+ refId!: number | null
28
+ }
29
+
30
+ let dataSource: DataSource
31
+ let repository: Repository<Widget>
32
+
33
+ beforeAll(async () => {
34
+ dataSource = new DataSource({
35
+ type: 'better-sqlite3',
36
+ database: ':memory:',
37
+ synchronize: true,
38
+ entities: [Widget]
39
+ })
40
+ await dataSource.initialize()
41
+ repository = dataSource.getRepository(Widget)
42
+
43
+ await repository.save([
44
+ { id: 1, flag: true, title: 'a', refId: 10 },
45
+ { id: 2, flag: false, title: '', refId: null },
46
+ { id: 3, flag: null, title: null, refId: 0 }
47
+ ])
48
+ })
49
+
50
+ afterAll(async () => {
51
+ await dataSource?.destroy()
52
+ })
53
+
54
+ /** 단일 필터로 조회한 결과 id 목록(정렬) */
55
+ async function idsFor(name: string, operator: string): Promise<number[]> {
56
+ const params = { filters: [{ name, operator, value: null }] } as unknown as ListParam
57
+ const qb = getQueryBuilderFromListParams({ repository, params })
58
+ const rows = await qb.getMany()
59
+ return rows.map(r => r.id).sort((a, b) => a - b)
60
+ }
61
+
62
+ describe('list-param filter operators — SQLite 실행 결과 (이식성 SQL)', () => {
63
+ it('is_true / is_false (boolean 파라미터 바인딩)', async () => {
64
+ expect(await idsFor('flag', 'is_true')).toEqual([1])
65
+ expect(await idsFor('flag', 'is_false')).toEqual([2])
66
+ })
67
+
68
+ it('is_not_true / is_not_false (NULL 포함 의미 보존)', async () => {
69
+ // NOT TRUE = false 또는 NULL, NOT FALSE = true 또는 NULL
70
+ expect(await idsFor('flag', 'is_not_true')).toEqual([2, 3])
71
+ expect(await idsFor('flag', 'is_not_false')).toEqual([1, 3])
72
+ })
73
+
74
+ it('is_present / is_blank (값 있음 / 없음)', async () => {
75
+ expect(await idsFor('title', 'is_present')).toEqual([1, 2]) // IS NOT NULL ('' 은 not null)
76
+ expect(await idsFor('title', 'is_blank')).toEqual([3]) // IS NULL
77
+ })
78
+
79
+ it('is_empty_num_id (NULL 또는 0)', async () => {
80
+ expect(await idsFor('refId', 'is_empty_num_id')).toEqual([2, 3])
81
+ })
82
+
83
+ it('is_null / is_not_null (기존 연산자 회귀 확인)', async () => {
84
+ expect(await idsFor('flag', 'is_null')).toEqual([3])
85
+ expect(await idsFor('flag', 'is_not_null')).toEqual([1, 2])
86
+ })
87
+ })
@@ -0,0 +1,38 @@
1
+ import type { ThingsFactoryClientConfig, ThingsFactoryServerModule } from '@things-factory/env'
2
+
3
+ /**
4
+ * 모듈 매니페스트 계약 파일럿 (P1 4단계).
5
+ *
6
+ * 실제 모듈이 취하는 형태(클라이언트 config / 서버 export)가 매니페스트 타입을 만족하는지
7
+ * 컴파일 타임(ts-jest)에 고정한다. 형태가 계약과 어긋나면 이 스위트가 컴파일에 실패한다.
8
+ *
9
+ * 참고: things-factory.config.js 는 babel(preset-typescript)로 컴파일되어 타입이 검사되지 않으므로
10
+ * (satisfies 도 그냥 제거됨), 계약 검증은 이처럼 tsc/ts-jest 가 타입 체크하는 지점에서 한다.
11
+ * 모듈이 자발적으로 계약을 채택하려면 tsc 로 검사되는 코드(서버 export 등)에서 satisfies 를 쓰거나
12
+ * 이와 같은 타입 어서션을 두면 된다.
13
+ */
14
+
15
+ // 클라이언트 매니페스트 — shell 의 실제 things-factory.config 형태
16
+ const clientConfig = {
17
+ bootstrap: () => {},
18
+ route: (page: string) => page,
19
+ routes: [{ tagname: 'page-404', page: 'page404' }]
20
+ } satisfies ThingsFactoryClientConfig
21
+
22
+ // 서버 모듈 — 대표적인 named export 형태(schema/entities/migrations/initMiddlewares)
23
+ const serverModule = {
24
+ schema: { resolverClasses: [class SampleResolver {}], typeDefs: {}, resolvers: {}, directives: {} },
25
+ entities: [class SampleEntity {}],
26
+ migrations: [],
27
+ subscribers: [],
28
+ initMiddlewares: (_app: unknown) => {}
29
+ } satisfies ThingsFactoryServerModule
30
+
31
+ describe('모듈 매니페스트 계약 (P1)', () => {
32
+ it('클라이언트/서버 형태가 매니페스트 타입을 만족한다 (컴파일 타임 검증)', () => {
33
+ expect(clientConfig.routes.length).toBe(1)
34
+ expect(clientConfig.routes[0].tagname).toBe('page-404')
35
+ expect(Array.isArray(serverModule.entities)).toBe(true)
36
+ expect(typeof serverModule.initMiddlewares).toBe('function')
37
+ })
38
+ })
package/client/store.ts DELETED
@@ -1,15 +0,0 @@
1
- import { configureStore } from '@reduxjs/toolkit'
2
-
3
- import app from './reducers/app.js'
4
- import route from './reducers/route.js'
5
-
6
- export const store = configureStore({
7
- // set false due to causing severe conflicts with redux-devtools.
8
- // devTools: false // process.env['NODE-ENV'] !== 'production'
9
- devTools: process.env['NODE-ENV'] !== 'production'
10
- })
11
-
12
- store.addReducers({
13
- app,
14
- route
15
- })