on-zero 0.8.4 → 0.9.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.
- package/dist/cjs/generate-layout.cjs +30 -11
- package/dist/cjs/generate-layout.native.js +37 -12
- package/dist/cjs/generate-layout.native.js.map +1 -1
- package/dist/cjs/generate-lite.cjs +26 -18
- package/dist/cjs/generate-lite.native.js +33 -27
- package/dist/cjs/generate-lite.native.js.map +1 -1
- package/dist/cjs/generate-lite.test.cjs +100 -9
- package/dist/cjs/generate-lite.test.native.js +102 -9
- package/dist/cjs/generate-lite.test.native.js.map +1 -1
- package/dist/cjs/generate.cjs +2 -2
- package/dist/cjs/generate.native.js +2 -6
- package/dist/cjs/generate.native.js.map +1 -1
- package/dist/cjs/generate.test.cjs +20 -0
- package/dist/cjs/generate.test.native.js +20 -0
- package/dist/cjs/generate.test.native.js.map +1 -1
- package/dist/esm/generate-layout.mjs +30 -11
- package/dist/esm/generate-layout.mjs.map +1 -1
- package/dist/esm/generate-layout.native.js +37 -12
- package/dist/esm/generate-layout.native.js.map +1 -1
- package/dist/esm/generate-lite.mjs +26 -18
- package/dist/esm/generate-lite.mjs.map +1 -1
- package/dist/esm/generate-lite.native.js +33 -27
- package/dist/esm/generate-lite.native.js.map +1 -1
- package/dist/esm/generate-lite.test.mjs +100 -9
- package/dist/esm/generate-lite.test.mjs.map +1 -1
- package/dist/esm/generate-lite.test.native.js +102 -9
- package/dist/esm/generate-lite.test.native.js.map +1 -1
- package/dist/esm/generate.mjs +2 -2
- package/dist/esm/generate.mjs.map +1 -1
- package/dist/esm/generate.native.js +2 -6
- package/dist/esm/generate.native.js.map +1 -1
- package/dist/esm/generate.test.mjs +20 -0
- package/dist/esm/generate.test.mjs.map +1 -1
- package/dist/esm/generate.test.native.js +20 -0
- package/dist/esm/generate.test.native.js.map +1 -1
- package/package.json +1 -1
- package/src/generate-layout.ts +32 -13
- package/src/generate-lite.test.ts +125 -8
- package/src/generate-lite.ts +46 -23
- package/src/generate.test.ts +29 -0
- package/src/generate.ts +2 -2
- package/types/generate-layout.d.ts +1 -0
- package/types/generate-layout.d.ts.map +1 -1
- package/types/generate-lite.d.ts +2 -1
- package/types/generate-lite.d.ts.map +1 -1
package/src/generate-layout.ts
CHANGED
|
@@ -16,6 +16,7 @@ export type DataInstance = {
|
|
|
16
16
|
dir: string
|
|
17
17
|
scope: string | null
|
|
18
18
|
namespaces: DataNamespace[]
|
|
19
|
+
tables: string[]
|
|
19
20
|
syncTables: string[]
|
|
20
21
|
supportTables: string[]
|
|
21
22
|
/** `supportTables` declared in `on-zero.config.ts`. */
|
|
@@ -522,11 +523,11 @@ function tableColumns(
|
|
|
522
523
|
return columns
|
|
523
524
|
}
|
|
524
525
|
|
|
525
|
-
function
|
|
526
|
+
function queriedTables(
|
|
526
527
|
ts: typeof import('typescript'),
|
|
527
528
|
namespace: DataNamespace,
|
|
528
529
|
relations: Map<string, Map<string, string>>
|
|
529
|
-
): Array<{ table: string; query: string }> {
|
|
530
|
+
): Array<{ table: string; query: string; root: boolean }> {
|
|
530
531
|
if (!namespace.queryPath) return []
|
|
531
532
|
const source = ts.createSourceFile(
|
|
532
533
|
namespace.queryPath,
|
|
@@ -534,7 +535,7 @@ function relatedTables(
|
|
|
534
535
|
ts.ScriptTarget.Latest,
|
|
535
536
|
true
|
|
536
537
|
)
|
|
537
|
-
const reached: Array<{ table: string; query: string }> = []
|
|
538
|
+
const reached: Array<{ table: string; query: string; root: boolean }> = []
|
|
538
539
|
const functions = new Map<string, ts.ConciseBody>()
|
|
539
540
|
const exported = new Set<string>()
|
|
540
541
|
|
|
@@ -593,7 +594,7 @@ function relatedTables(
|
|
|
593
594
|
`from table '${sourceTable}' through relations.ts`
|
|
594
595
|
)
|
|
595
596
|
}
|
|
596
|
-
reached.push({ table: target, query })
|
|
597
|
+
reached.push({ table: target, query, root: false })
|
|
597
598
|
visit(node.expression.expression, currentTable, query)
|
|
598
599
|
const callback = node.arguments[1]
|
|
599
600
|
if (
|
|
@@ -609,7 +610,9 @@ function relatedTables(
|
|
|
609
610
|
const key = `${query}:${node.expression.text}`
|
|
610
611
|
if (helper && !visiting.has(key)) {
|
|
611
612
|
visiting.add(key)
|
|
612
|
-
|
|
613
|
+
const helperRoot = rootTable(helper)
|
|
614
|
+
if (helperRoot) reached.push({ table: helperRoot, query, root: true })
|
|
615
|
+
visit(helper, helperRoot ?? currentTable, query)
|
|
613
616
|
visiting.delete(key)
|
|
614
617
|
}
|
|
615
618
|
}
|
|
@@ -618,7 +621,10 @@ function relatedTables(
|
|
|
618
621
|
|
|
619
622
|
for (const name of exported) {
|
|
620
623
|
if (['mutate', 'schema', 'where'].includes(name)) continue
|
|
621
|
-
|
|
624
|
+
const body = functions.get(name)!
|
|
625
|
+
const queryRoot = rootTable(body)
|
|
626
|
+
if (queryRoot) reached.push({ table: queryRoot, query: name, root: true })
|
|
627
|
+
visit(body, queryRoot ?? namespace.name, name)
|
|
622
628
|
}
|
|
623
629
|
return reached
|
|
624
630
|
}
|
|
@@ -776,6 +782,7 @@ export function discoverDataLayout(
|
|
|
776
782
|
dir: instance.dir,
|
|
777
783
|
scope: instance.scope,
|
|
778
784
|
namespaces: [],
|
|
785
|
+
tables: [],
|
|
779
786
|
syncTables: [],
|
|
780
787
|
supportTables: [],
|
|
781
788
|
declaredSupportTables: instance.supportTables,
|
|
@@ -786,26 +793,36 @@ export function discoverDataLayout(
|
|
|
786
793
|
instance.namespaces = discoverNamespaces(ts, baseDir, instance, instanceDirs)
|
|
787
794
|
}
|
|
788
795
|
const namespaces = instances.flatMap((instance) => instance.namespaces)
|
|
789
|
-
const
|
|
796
|
+
const namespaceOwners = new Map<string, string>()
|
|
790
797
|
for (const namespace of namespaces) {
|
|
791
|
-
const owner =
|
|
798
|
+
const owner = namespaceOwners.get(namespace.name)
|
|
792
799
|
if (owner) {
|
|
793
800
|
throw new Error(
|
|
794
801
|
`[on-zero] namespace '${namespace.name}' is claimed by instances '${owner}' and '${namespace.instance}'`
|
|
795
802
|
)
|
|
796
803
|
}
|
|
797
|
-
|
|
804
|
+
namespaceOwners.set(namespace.name, namespace.instance)
|
|
798
805
|
}
|
|
806
|
+
const tableOwners = new Map(
|
|
807
|
+
namespaces
|
|
808
|
+
.filter((namespace) => namespace.modelPath !== null)
|
|
809
|
+
.map((namespace) => [namespace.name, namespace.instance])
|
|
810
|
+
)
|
|
799
811
|
|
|
800
812
|
const metadata = metadataPaths(baseDir)
|
|
801
813
|
const relations = relationTargets(ts, metadata)
|
|
802
814
|
const columns = tableColumns(ts, metadata, namespaces)
|
|
803
815
|
const relatedOwners = new Map<string, string>()
|
|
804
816
|
for (const instance of instances) {
|
|
805
|
-
const
|
|
817
|
+
const tables = new Set(
|
|
818
|
+
instance.namespaces
|
|
819
|
+
.filter((namespace) => namespace.modelPath !== null)
|
|
820
|
+
.map((namespace) => namespace.name)
|
|
821
|
+
)
|
|
822
|
+
const syncTables = new Set(tables)
|
|
806
823
|
for (const namespace of instance.namespaces) {
|
|
807
|
-
for (const reached of
|
|
808
|
-
const owner =
|
|
824
|
+
for (const reached of queriedTables(ts, namespace, relations)) {
|
|
825
|
+
const owner = tableOwners.get(reached.table) ?? relatedOwners.get(reached.table)
|
|
809
826
|
if (owner && owner !== instance.name) {
|
|
810
827
|
throw new Error(
|
|
811
828
|
`[on-zero] ${namespace.name}.${reached.query} in instance '${instance.name}' reaches ` +
|
|
@@ -813,9 +830,11 @@ export function discoverDataLayout(
|
|
|
813
830
|
)
|
|
814
831
|
}
|
|
815
832
|
relatedOwners.set(reached.table, instance.name)
|
|
833
|
+
if (reached.root) tables.add(reached.table)
|
|
816
834
|
syncTables.add(reached.table)
|
|
817
835
|
}
|
|
818
836
|
}
|
|
837
|
+
instance.tables = [...tables].sort()
|
|
819
838
|
instance.syncTables = [...syncTables].sort()
|
|
820
839
|
if (instance.scope) {
|
|
821
840
|
for (const table of instance.syncTables) {
|
|
@@ -836,7 +855,7 @@ export function discoverDataLayout(
|
|
|
836
855
|
const supportTables = new Set<string>(instance.declaredSupportTables)
|
|
837
856
|
for (const namespace of instance.namespaces) {
|
|
838
857
|
for (const table of mutationSupportTables(ts, baseDir, sourceRoots, namespace)) {
|
|
839
|
-
if (
|
|
858
|
+
if (tableOwners.has(table) || relatedOwners.has(table)) continue
|
|
840
859
|
if (!instance.syncTables.includes(table)) {
|
|
841
860
|
supportTables.add(table)
|
|
842
861
|
}
|
|
@@ -298,21 +298,43 @@ describe('generateLite', () => {
|
|
|
298
298
|
mutations: [],
|
|
299
299
|
queries: [
|
|
300
300
|
// no-arg query → void
|
|
301
|
-
{ name: 'allPosts', paramTypeText: null },
|
|
301
|
+
{ name: 'allPosts', rootTable: 'post', paramTypeText: null, relatedPaths: [] },
|
|
302
302
|
// inline object → real validator
|
|
303
|
-
{
|
|
303
|
+
{
|
|
304
|
+
name: 'postById',
|
|
305
|
+
rootTable: 'post',
|
|
306
|
+
paramTypeText: '{ id: string }',
|
|
307
|
+
relatedPaths: [],
|
|
308
|
+
},
|
|
304
309
|
// primitive
|
|
305
|
-
{
|
|
310
|
+
{
|
|
311
|
+
name: 'byAuthorId',
|
|
312
|
+
rootTable: 'post',
|
|
313
|
+
paramTypeText: 'string',
|
|
314
|
+
relatedPaths: [],
|
|
315
|
+
},
|
|
306
316
|
// optional nullable inline object
|
|
307
317
|
{
|
|
308
318
|
name: 'paged',
|
|
319
|
+
rootTable: 'post',
|
|
309
320
|
paramTypeText:
|
|
310
321
|
'{ pageSize: number; cursor?: { id: string; createdAt: number } | null }',
|
|
322
|
+
relatedPaths: [],
|
|
311
323
|
},
|
|
312
324
|
// type reference → fallback
|
|
313
|
-
{
|
|
325
|
+
{
|
|
326
|
+
name: 'filtered',
|
|
327
|
+
rootTable: 'post',
|
|
328
|
+
paramTypeText: 'PostFilter',
|
|
329
|
+
relatedPaths: [],
|
|
330
|
+
},
|
|
314
331
|
// permission should be skipped
|
|
315
|
-
{
|
|
332
|
+
{
|
|
333
|
+
name: 'permission',
|
|
334
|
+
rootTable: 'post',
|
|
335
|
+
paramTypeText: null,
|
|
336
|
+
relatedPaths: [],
|
|
337
|
+
},
|
|
316
338
|
],
|
|
317
339
|
},
|
|
318
340
|
}
|
|
@@ -473,7 +495,14 @@ describe('generateLite', () => {
|
|
|
473
495
|
parse: makeParse({
|
|
474
496
|
[`${DIR}/server.ts`]: {
|
|
475
497
|
mutations: [],
|
|
476
|
-
queries: [
|
|
498
|
+
queries: [
|
|
499
|
+
{
|
|
500
|
+
name: 'serverRows',
|
|
501
|
+
rootTable: 'server',
|
|
502
|
+
paramTypeText: null,
|
|
503
|
+
relatedPaths: [],
|
|
504
|
+
},
|
|
505
|
+
],
|
|
477
506
|
},
|
|
478
507
|
[`${DIR}/types.ts`]: {
|
|
479
508
|
mutations: [],
|
|
@@ -499,7 +528,14 @@ describe('generateLite', () => {
|
|
|
499
528
|
return {
|
|
500
529
|
mutations: [],
|
|
501
530
|
queries: source.includes('zql.server')
|
|
502
|
-
? [
|
|
531
|
+
? [
|
|
532
|
+
{
|
|
533
|
+
name: 'serverRows',
|
|
534
|
+
rootTable: 'server',
|
|
535
|
+
paramTypeText: null,
|
|
536
|
+
relatedPaths: [],
|
|
537
|
+
},
|
|
538
|
+
]
|
|
503
539
|
: [],
|
|
504
540
|
}
|
|
505
541
|
},
|
|
@@ -545,6 +581,7 @@ describe('generateLite', () => {
|
|
|
545
581
|
queries: [
|
|
546
582
|
{
|
|
547
583
|
name: 'messages',
|
|
584
|
+
rootTable: 'message',
|
|
548
585
|
paramTypeText: null,
|
|
549
586
|
relatedPaths: [['comments', 'author']],
|
|
550
587
|
},
|
|
@@ -594,6 +631,79 @@ describe('generateLite', () => {
|
|
|
594
631
|
expect(instance?.supportTables).toEqual([])
|
|
595
632
|
})
|
|
596
633
|
|
|
634
|
+
test('derives query membership from the query root instead of its namespace', () => {
|
|
635
|
+
const files = {
|
|
636
|
+
[`${DIR}/category/mutations.ts`]: '// fake category model',
|
|
637
|
+
[`${DIR}/dashboard/queries.ts`]: `export const monthSummary = () => zql.category.related('expenses')`,
|
|
638
|
+
['/proj/src/database/relations.ts']: '// fake relations',
|
|
639
|
+
['/proj/src/database/schema.ts']: '// fake tables',
|
|
640
|
+
}
|
|
641
|
+
const empty = { mutations: [], queries: [] }
|
|
642
|
+
const result = generateLite({
|
|
643
|
+
files,
|
|
644
|
+
dir: DIR,
|
|
645
|
+
parse: makeParse({
|
|
646
|
+
[`${DIR}/category/mutations.ts`]: {
|
|
647
|
+
...empty,
|
|
648
|
+
mutations: [
|
|
649
|
+
{
|
|
650
|
+
modelName: 'category',
|
|
651
|
+
handlers: [],
|
|
652
|
+
schema: null,
|
|
653
|
+
},
|
|
654
|
+
],
|
|
655
|
+
},
|
|
656
|
+
[`${DIR}/dashboard/queries.ts`]: {
|
|
657
|
+
...empty,
|
|
658
|
+
queries: [
|
|
659
|
+
{
|
|
660
|
+
name: 'monthSummary',
|
|
661
|
+
rootTable: 'category',
|
|
662
|
+
paramTypeText: null,
|
|
663
|
+
relatedPaths: [['expenses']],
|
|
664
|
+
},
|
|
665
|
+
],
|
|
666
|
+
},
|
|
667
|
+
'/proj/src/database/relations.ts': {
|
|
668
|
+
...empty,
|
|
669
|
+
relations: [
|
|
670
|
+
{
|
|
671
|
+
sourceTable: 'category',
|
|
672
|
+
name: 'expenses',
|
|
673
|
+
targetTable: 'expense',
|
|
674
|
+
},
|
|
675
|
+
],
|
|
676
|
+
},
|
|
677
|
+
'/proj/src/database/schema.ts': {
|
|
678
|
+
...empty,
|
|
679
|
+
tables: [
|
|
680
|
+
{ name: 'category', columns: ['id'] },
|
|
681
|
+
{ name: 'expense', columns: ['id', 'categoryId'] },
|
|
682
|
+
],
|
|
683
|
+
},
|
|
684
|
+
}),
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
expect(result.instances[0]?.syncTables).toEqual(['category', 'expense'])
|
|
688
|
+
expect(result.instances[0]?.syncTables).not.toContain('dashboard')
|
|
689
|
+
})
|
|
690
|
+
|
|
691
|
+
test('ignores related syntax mentioned only in a query-file comment', () => {
|
|
692
|
+
const files = {
|
|
693
|
+
[`${DIR}/dashboard/queries.ts`]: `// monthSummary moved to category/queries.ts because it uses .related()`,
|
|
694
|
+
}
|
|
695
|
+
const result = generateLite({
|
|
696
|
+
files,
|
|
697
|
+
dir: DIR,
|
|
698
|
+
parse: makeParse({
|
|
699
|
+
[`${DIR}/dashboard/queries.ts`]: { mutations: [], queries: [] },
|
|
700
|
+
}),
|
|
701
|
+
})
|
|
702
|
+
|
|
703
|
+
expect(result.queryCount).toBe(0)
|
|
704
|
+
expect(result.instances[0]?.syncTables).toEqual([])
|
|
705
|
+
})
|
|
706
|
+
|
|
597
707
|
test('derives fileless support tables through parsed mutation helpers', () => {
|
|
598
708
|
const files = {
|
|
599
709
|
[`${DIR}/post.ts`]: '// namespace',
|
|
@@ -736,7 +846,14 @@ describe('generateLite', () => {
|
|
|
736
846
|
},
|
|
737
847
|
[`${DIR}/account.ts`]: {
|
|
738
848
|
...empty,
|
|
739
|
-
queries: [
|
|
849
|
+
queries: [
|
|
850
|
+
{
|
|
851
|
+
name: 'accounts',
|
|
852
|
+
rootTable: 'account',
|
|
853
|
+
paramTypeText: null,
|
|
854
|
+
relatedPaths: [],
|
|
855
|
+
},
|
|
856
|
+
],
|
|
740
857
|
},
|
|
741
858
|
[`${DIR}/project/message.ts`]: {
|
|
742
859
|
...empty,
|
package/src/generate-lite.ts
CHANGED
|
@@ -67,13 +67,17 @@ export type LiteSchemaInfo = {
|
|
|
67
67
|
export type LiteQueryExport = {
|
|
68
68
|
// exported variable name, e.g. 'flightById'
|
|
69
69
|
name: string
|
|
70
|
+
// table at the root of the returned query builder, e.g. `post` for
|
|
71
|
+
// `zql.post.where(...)`. query namespaces may group queries for another
|
|
72
|
+
// table, so this cannot be inferred from the source filename.
|
|
73
|
+
rootTable: string
|
|
70
74
|
// text of the first parameter's type annotation, if present.
|
|
71
75
|
// e.g. 'string' | '{ id: string }' | null. null means the query takes no
|
|
72
76
|
// args and is treated as a void query in the generated output.
|
|
73
77
|
paramTypeText: string | null
|
|
74
|
-
// relation-name paths starting at
|
|
75
|
-
//
|
|
76
|
-
relatedPaths
|
|
78
|
+
// relation-name paths starting at rootTable. nested related() calls are one
|
|
79
|
+
// path, e.g. [['comments', 'author']].
|
|
80
|
+
relatedPaths: string[][]
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
export type LiteRelationInfo = {
|
|
@@ -544,7 +548,10 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
|
|
|
544
548
|
sourceFile: string
|
|
545
549
|
importPath: string
|
|
546
550
|
}> = []
|
|
547
|
-
const
|
|
551
|
+
const queryPaths = new Map<
|
|
552
|
+
string,
|
|
553
|
+
Array<{ query: string; rootTable: string; paths: string[][] }>
|
|
554
|
+
>()
|
|
548
555
|
|
|
549
556
|
for (const namespace of namespaces.filter(
|
|
550
557
|
(namespace): namespace is LiteNamespace & { queryPath: string } =>
|
|
@@ -552,24 +559,22 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
|
|
|
552
559
|
)) {
|
|
553
560
|
const filePath = namespace.queryPath
|
|
554
561
|
const fileBaseName = namespace.name
|
|
555
|
-
const
|
|
556
|
-
const parsed = parse(content, filePath)
|
|
557
|
-
if (
|
|
558
|
-
content.includes('.related(') &&
|
|
559
|
-
!parsed.queries.some((query) => query.relatedPaths)
|
|
560
|
-
) {
|
|
561
|
-
throw new Error(
|
|
562
|
-
`[on-zero] ${filePath} uses related(), but the lite parser did not return relatedPaths`
|
|
563
|
-
)
|
|
564
|
-
}
|
|
562
|
+
const parsed = parse(files[filePath]!, filePath)
|
|
565
563
|
|
|
566
564
|
for (const q of parsed.queries) {
|
|
567
565
|
if (['mutate', 'permission', 'schema', 'where'].includes(q.name)) continue
|
|
568
|
-
if (q.relatedPaths
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
566
|
+
if (!q.rootTable || !Array.isArray(q.relatedPaths)) {
|
|
567
|
+
throw new Error(
|
|
568
|
+
`[on-zero] ${filePath} query '${q.name}' is missing lite parser query metadata`
|
|
569
|
+
)
|
|
572
570
|
}
|
|
571
|
+
const entries = queryPaths.get(namespace.name) ?? []
|
|
572
|
+
entries.push({
|
|
573
|
+
query: q.name,
|
|
574
|
+
rootTable: q.rootTable,
|
|
575
|
+
paths: q.relatedPaths,
|
|
576
|
+
})
|
|
577
|
+
queryPaths.set(namespace.name, entries)
|
|
573
578
|
|
|
574
579
|
// null annotation → no first arg → void query
|
|
575
580
|
if (q.paramTypeText == null) {
|
|
@@ -608,16 +613,33 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
|
|
|
608
613
|
}
|
|
609
614
|
|
|
610
615
|
const owners = new Map(
|
|
611
|
-
|
|
616
|
+
modelNamespaces.map((namespace) => [namespace.name, namespace.instance])
|
|
612
617
|
)
|
|
613
618
|
const relatedOwners = new Map<string, string>()
|
|
619
|
+
const directTables = new Map<string, string[]>()
|
|
614
620
|
const syncTables = new Map<string, string[]>()
|
|
615
621
|
for (const instance of instances) {
|
|
616
|
-
const
|
|
622
|
+
const direct = new Set(
|
|
623
|
+
instance.namespaces
|
|
624
|
+
.filter((namespace) => namespace.modelPath !== null)
|
|
625
|
+
.map((namespace) => namespace.name)
|
|
626
|
+
)
|
|
627
|
+
const synced = new Set(direct)
|
|
617
628
|
for (const namespace of instance.namespaces) {
|
|
618
|
-
for (const query of
|
|
629
|
+
for (const query of queryPaths.get(namespace.name) ?? []) {
|
|
630
|
+
const rootOwner =
|
|
631
|
+
owners.get(query.rootTable) ?? relatedOwners.get(query.rootTable)
|
|
632
|
+
if (rootOwner && rootOwner !== instance.name) {
|
|
633
|
+
throw new Error(
|
|
634
|
+
`[on-zero] ${namespace.name}.${query.query} in instance '${instance.name}' reaches ` +
|
|
635
|
+
`table '${query.rootTable}' owned by instance '${rootOwner}'`
|
|
636
|
+
)
|
|
637
|
+
}
|
|
638
|
+
relatedOwners.set(query.rootTable, instance.name)
|
|
639
|
+
direct.add(query.rootTable)
|
|
640
|
+
synced.add(query.rootTable)
|
|
619
641
|
for (const path of query.paths) {
|
|
620
|
-
let sourceTable =
|
|
642
|
+
let sourceTable = query.rootTable
|
|
621
643
|
for (const relationName of path) {
|
|
622
644
|
const target = relations.get(sourceTable)?.get(relationName)
|
|
623
645
|
if (!target) {
|
|
@@ -640,6 +662,7 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
|
|
|
640
662
|
}
|
|
641
663
|
}
|
|
642
664
|
}
|
|
665
|
+
directTables.set(instance.name, [...direct].sort())
|
|
643
666
|
const tables = [...synced].sort()
|
|
644
667
|
if (instance.scope) {
|
|
645
668
|
for (const table of tables) {
|
|
@@ -734,7 +757,7 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
|
|
|
734
757
|
modelNames: instance.namespaces
|
|
735
758
|
.filter((namespace) => namespace.modelPath)
|
|
736
759
|
.map((namespace) => namespace.name),
|
|
737
|
-
tables:
|
|
760
|
+
tables: directTables.get(instance.name)!,
|
|
738
761
|
syncTables: syncTables.get(instance.name)!,
|
|
739
762
|
supportTables: supportTables.get(instance.name)!,
|
|
740
763
|
}))
|
package/src/generate.test.ts
CHANGED
|
@@ -320,6 +320,35 @@ export const userPublic = sqliteTable('user_public', { id: text(), projectId: te
|
|
|
320
320
|
)
|
|
321
321
|
})
|
|
322
322
|
|
|
323
|
+
test('derives query membership from the returned query root', async () => {
|
|
324
|
+
writeFileSync(
|
|
325
|
+
join(dataDir(), 'category/mutations.ts'),
|
|
326
|
+
`export const schema = table('category').columns({ id: string() })`
|
|
327
|
+
)
|
|
328
|
+
writeFileSync(
|
|
329
|
+
join(dataDir(), 'dashboard/queries.ts'),
|
|
330
|
+
`export const monthSummary = () => zql.category.related('expenses')`
|
|
331
|
+
)
|
|
332
|
+
writeFileSync(
|
|
333
|
+
join(testDir, 'src/database/relations.ts'),
|
|
334
|
+
`export const relations = defineRelations(schema, (r) => ({
|
|
335
|
+
category: { expenses: r.many.expense({}) },
|
|
336
|
+
}))`
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
await expect(deriveDataMembership({ dir: dataDir() })).resolves.toEqual({
|
|
340
|
+
instances: {
|
|
341
|
+
default: {
|
|
342
|
+
tables: ['category'],
|
|
343
|
+
syncTables: ['category', 'expense'],
|
|
344
|
+
supportTables: [],
|
|
345
|
+
scope: null,
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
allTables: ['category', 'expense'],
|
|
349
|
+
})
|
|
350
|
+
})
|
|
351
|
+
|
|
323
352
|
test('derives single-file namespaces from data exports', async () => {
|
|
324
353
|
writeFileSync(
|
|
325
354
|
join(dataDir(), 'server.ts'),
|
package/src/generate.ts
CHANGED
|
@@ -842,7 +842,7 @@ function dataMembershipFromLayout(layout: DataLayout): DataMembership {
|
|
|
842
842
|
layout.instances.map((instance) => [
|
|
843
843
|
instance.name,
|
|
844
844
|
{
|
|
845
|
-
tables: instance.
|
|
845
|
+
tables: [...instance.tables],
|
|
846
846
|
syncTables: [...instance.syncTables],
|
|
847
847
|
supportTables: [...instance.supportTables],
|
|
848
848
|
scope: instance.scope,
|
|
@@ -1188,7 +1188,7 @@ export async function generate(options: GenerateOptions): Promise<GenerateResult
|
|
|
1188
1188
|
modelNames: instance.namespaces
|
|
1189
1189
|
.filter((namespace) => namespace.modelPath)
|
|
1190
1190
|
.map((namespace) => namespace.name),
|
|
1191
|
-
tables: instance.
|
|
1191
|
+
tables: instance.tables,
|
|
1192
1192
|
syncTables: instance.syncTables,
|
|
1193
1193
|
supportTables: instance.supportTables,
|
|
1194
1194
|
}))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-layout.d.ts","sourceRoot":"","sources":["../src/generate-layout.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,uDAAuD;IACvD,qBAAqB,EAAE,MAAM,EAAE,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,YAAY,EAAE,CAAA;IACzB,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB,CAAA;
|
|
1
|
+
{"version":3,"file":"generate-layout.d.ts","sourceRoot":"","sources":["../src/generate-layout.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,uDAAuD;IACvD,qBAAqB,EAAE,MAAM,EAAE,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,YAAY,EAAE,CAAA;IACzB,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB,CAAA;AAstBD,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,YAAY,CAAC,EAC/B,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,UAAU,CAkHZ;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzE"}
|
package/types/generate-lite.d.ts
CHANGED
|
@@ -16,8 +16,9 @@ export type LiteSchemaInfo = {
|
|
|
16
16
|
};
|
|
17
17
|
export type LiteQueryExport = {
|
|
18
18
|
name: string;
|
|
19
|
+
rootTable: string;
|
|
19
20
|
paramTypeText: string | null;
|
|
20
|
-
relatedPaths
|
|
21
|
+
relatedPaths: string[][];
|
|
21
22
|
};
|
|
22
23
|
export type LiteRelationInfo = {
|
|
23
24
|
sourceTable: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-lite.d.ts","sourceRoot":"","sources":["../src/generate-lite.ts"],"names":[],"mappings":"AAkCA,MAAM,MAAM,kBAAkB,GAAG;IAK/B,SAAS,EAAE,MAAM,CAAA;IAEjB,QAAQ,EAAE,KAAK,CAAC;QAEd,IAAI,EAAE,MAAM,CAAA;QAMZ,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;KAC7B,CAAC,CAAA;IAKF,MAAM,EAAE,cAAc,GAAG,IAAI,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,EAAE,CAAA;IAGrB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACtD,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAE5B,IAAI,EAAE,MAAM,CAAA;IAIZ,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAG5B,YAAY,
|
|
1
|
+
{"version":3,"file":"generate-lite.d.ts","sourceRoot":"","sources":["../src/generate-lite.ts"],"names":[],"mappings":"AAkCA,MAAM,MAAM,kBAAkB,GAAG;IAK/B,SAAS,EAAE,MAAM,CAAA;IAEjB,QAAQ,EAAE,KAAK,CAAC;QAEd,IAAI,EAAE,MAAM,CAAA;QAMZ,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;KAC7B,CAAC,CAAA;IAKF,MAAM,EAAE,cAAc,GAAG,IAAI,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,EAAE,CAAA;IAGrB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACtD,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAE5B,IAAI,EAAE,MAAM,CAAA;IAIZ,SAAS,EAAE,MAAM,CAAA;IAIjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAG5B,YAAY,EAAE,MAAM,EAAE,EAAE,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CACf,MAAM,EACN;QACE,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;KACzB,CACF,CAAA;CACF,CAAA;AAGD,MAAM,MAAM,cAAc,GAAG;IAG3B,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC9B,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IAGxB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IAExB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAElB,UAAU,CAAC,EAAE,cAAc,CAAA;IAE3B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAID,MAAM,MAAM,WAAW,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,cAAc,CAAA;AAElF,MAAM,MAAM,mBAAmB,GAAG;IAGhC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAG7B,GAAG,EAAE,MAAM,CAAA;IAEX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,WAAW,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAG/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAI7B,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;IACjF,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AA4RD,wBAAgB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,kBAAkB,CAoW1E"}
|