[DBX-6933] Feat: Support custom metadata element#932
Conversation
Benchmark Resultdbml-parse
|
Coverage ReportCommit: 448489d Overall Coverage
Package Coverage
|
| File | Lines | Statements | Functions | Branches |
|---|---|---|---|---|
src/connectors/bigquery/index.ts |
0.00% | 0.00% | 0.00% | 0.00% |
src/utils/credential-loader.ts |
0.00% | 0.00% | 0.00% | 0.00% |
src/utils/helpers.ts |
0.00% | 0.00% | 0.00% | 0.00% |
src/connectors/snowflake/index.ts |
10.56% | 10.31% | 0.00% | 0.00% |
src/utils/parseSchema.ts |
46.15% | 42.85% | 28.57% | 27.27% |
src/connectors/connector.ts |
66.66% | 66.66% | 100.00% | 57.14% |
src/connectors/oracle/tables.ts |
71.25% | 67.39% | 100.00% | 56.96% |
src/connectors/oracle/index.ts |
80.00% | 80.76% | 100.00% | 25.00% |
src/connectors/oracle/utils.ts |
85.71% | 85.71% | 100.00% | 71.42% |
dbml-parse
82 file(s) below 80% coverage
| File | Lines | Statements | Functions | Branches |
|---|---|---|---|---|
src/compiler/queries/container/scope.ts |
0.00% | 0.00% | 0.00% | 0.00% |
src/services/diagnostics/provider.ts |
0.00% | 0.00% | 0.00% | 0.00% |
src/compiler/queries/pipeline/interpret.ts |
11.76% | 13.51% | 66.66% | 41.66% |
src/services/suggestions/crossFile.ts |
19.35% | 19.44% | 33.33% | 10.00% |
src/core/local_modules/enum/index.ts |
48.00% | 46.29% | 57.14% | 52.63% |
src/core/global_modules/project/interpret.ts |
52.50% | 46.66% | 83.33% | 23.07% |
src/compiler/projectLayout/layout.ts |
54.16% | 53.84% | 75.00% | 52.63% |
src/core/local_modules/metadata/index.ts |
55.55% | 61.53% | 75.00% | 50.00% |
src/compiler/queries/legacy/parse.ts |
61.53% | 53.33% | 66.66% | 25.00% |
src/core/local_modules/ref/index.ts |
62.50% | 61.76% | 100.00% | 57.14% |
src/core/types/report.ts |
62.50% | 55.55% | 75.00% | 57.14% |
src/core/global_modules/records/utils/data/values.ts |
63.30% | 55.71% | 72.72% | 49.28% |
src/core/types/symbol/symbols.ts |
63.70% | 56.00% | 59.83% | 45.00% |
src/core/local_modules/tableGroup/validate.ts |
64.55% | 64.44% | 71.42% | 58.00% |
src/compiler/queries/legacy/token.ts |
66.66% | 66.66% | 66.66% | 100.00% |
src/core/global_modules/enum/bind.ts |
66.66% | 68.75% | 83.33% | 50.00% |
src/core/local_modules/program/index.ts |
66.66% | 69.23% | 75.00% | 62.50% |
src/core/global_modules/note/bind.ts |
69.23% | 71.42% | 83.33% | 50.00% |
src/core/local_modules/checks/index.ts |
69.23% | 75.00% | 100.00% | 64.28% |
src/core/local_modules/project/index.ts |
69.23% | 69.23% | 100.00% | 63.63% |
src/core/local_modules/custom/index.ts |
70.58% | 71.42% | 80.00% | 68.75% |
src/compiler/queries/utils.ts |
73.10% | 73.38% | 90.90% | 51.11% |
src/core/local_modules/tablePartial/validate.ts |
73.12% | 71.83% | 79.22% | 57.67% |
src/core/global_modules/project/bind.ts |
73.33% | 75.00% | 100.00% | 50.00% |
src/core/local_modules/indexes/index.ts |
73.68% | 69.35% | 63.63% | 64.28% |
src/core/local_modules/use/index.ts |
73.91% | 75.00% | 75.00% | 78.12% |
src/core/local_modules/indexes/validate.ts |
74.28% | 74.66% | 90.90% | 56.00% |
src/core/local_modules/note/index.ts |
75.00% | 75.86% | 75.00% | 72.72% |
src/services/suggestions/utils/index.ts |
75.00% | 75.00% | 100.00% | 62.06% |
src/core/parser/utils.ts |
75.28% | 75.56% | 100.00% | 81.67% |
src/core/local_modules/records/index.ts |
75.60% | 76.19% | 100.00% | 68.08% |
src/core/local_modules/project/validate.ts |
75.86% | 75.86% | 100.00% | 56.25% |
src/core/global_modules/indexes/bind.ts |
76.31% | 74.35% | 90.90% | 68.96% |
src/core/global_modules/records/utils/data/sqlTypes.ts |
76.59% | 80.64% | 82.35% | 72.22% |
src/core/global_modules/tablePartial/interpret.ts |
77.89% | 70.64% | 78.94% | 53.73% |
src/core/local_modules/note/validate.ts |
78.00% | 76.36% | 83.33% | 71.05% |
src/core/types/filepath.ts |
79.48% | 78.57% | 77.77% | 70.37% |
src/core/global_modules/utils.ts |
79.54% | 75.51% | 72.72% | 63.63% |
src/core/global_modules/program/utils.ts |
80.00% | 80.00% | 100.00% | 70.00% |
src/core/global_modules/tableGroup/bind.ts |
80.00% | 80.00% | 100.00% | 57.14% |
__tests__/utils/compiler.ts |
80.27% | 77.27% | 100.00% | 54.68% |
src/core/local_modules/records/validate.ts |
80.28% | 80.55% | 93.75% | 72.30% |
src/core/global_modules/indexes/interpret.ts |
81.39% | 72.00% | 100.00% | 56.66% |
src/core/local_modules/tablePartial/index.ts |
81.48% | 81.48% | 100.00% | 77.27% |
src/core/local_modules/diagramView/validate.ts |
81.57% | 78.04% | 84.21% | 72.72% |
src/core/local_modules/checks/validate.ts |
81.63% | 82.69% | 93.75% | 70.00% |
src/core/local_modules/metadata/validate.ts |
82.22% | 84.00% | 100.00% | 71.79% |
src/core/parser/parser.ts |
82.72% | 82.98% | 100.00% | 73.71% |
src/core/global_modules/records/bind.ts |
82.92% | 83.72% | 93.75% | 67.30% |
src/compiler/queries/container/token.ts |
83.33% | 85.71% | 100.00% | 75.00% |
src/core/global_modules/ref/bind.ts |
83.87% | 83.87% | 90.00% | 75.00% |
src/core/global_modules/records/utils/constraints/pk.ts |
84.61% | 81.42% | 92.59% | 56.52% |
src/core/local_modules/table/validate.ts |
84.92% | 85.47% | 90.24% | 73.40% |
src/core/local_modules/enum/validate.ts |
85.48% | 81.81% | 81.25% | 76.31% |
src/services/suggestions/provider.ts |
86.01% | 82.16% | 93.93% | 74.18% |
src/services/suggestions/utils/useMerger.ts |
86.95% | 81.13% | 100.00% | 46.34% |
src/core/global_modules/tablePartial/bind.ts |
87.03% | 87.27% | 100.00% | 71.42% |
src/core/global_modules/tableGroup/interpret.ts |
88.37% | 88.37% | 100.00% | 77.27% |
src/services/suggestions/recordRowSnippet.ts |
88.46% | 87.09% | 100.00% | 73.80% |
src/compiler/queries/nodeAtPosition.ts |
88.88% | 90.00% | 100.00% | 75.00% |
src/core/global_modules/diagramView/index.ts |
89.16% | 86.23% | 83.33% | 78.18% |
src/core/global_modules/metadata/resolve.ts |
90.47% | 78.57% | 100.00% | 72.00% |
src/core/global_modules/table/interpret.ts |
90.69% | 84.72% | 95.45% | 67.70% |
src/compiler/index.ts |
90.76% | 90.83% | 75.00% | 78.84% |
src/core/global_modules/records/index.ts |
90.90% | 87.15% | 100.00% | 79.16% |
src/core/global_modules/schema/index.ts |
92.26% | 82.46% | 91.66% | 70.07% |
src/core/types/symbol/metadata.ts |
92.46% | 77.55% | 97.72% | 63.06% |
src/core/global_modules/diagramView/interpret.ts |
94.59% | 90.40% | 92.85% | 75.75% |
src/services/suggestions/use.ts |
94.68% | 87.61% | 100.00% | 77.45% |
src/core/utils/interpret.ts |
95.00% | 91.25% | 100.00% | 74.64% |
src/core/global_modules/note/interpret.ts |
95.65% | 95.65% | 100.00% | 75.00% |
src/core/global_modules/records/interpret.ts |
95.97% | 92.59% | 100.00% | 79.54% |
__tests__/examples/interpreter/multifile/utils.ts |
96.00% | 89.65% | 100.00% | 62.50% |
src/compiler/queries/canonicalName.ts |
96.96% | 92.10% | 100.00% | 76.66% |
src/core/global_modules/program/interpret.ts |
97.46% | 92.17% | 100.00% | 70.74% |
src/core/types/errors.ts |
98.55% | 98.55% | 66.66% | 100.00% |
src/compiler/queries/transform/renameTable.ts |
99.05% | 90.47% | 100.00% | 78.82% |
src/core/global_modules/checks/interpret.ts |
100.00% | 88.88% | 100.00% | 60.00% |
src/core/global_modules/metadata/interpret.ts |
100.00% | 90.47% | 100.00% | 76.66% |
src/core/global_modules/program/index.ts |
100.00% | 85.71% | 100.00% | 75.00% |
src/core/global_modules/records/utils/constraints/unique.ts |
100.00% | 95.00% | 100.00% | 62.50% |
src/services/definition/provider.ts |
100.00% | 95.23% | 100.00% | 71.42% |
5ed7ff2 to
15457bb
Compare
76bfb1a to
52c916e
Compare
There was a problem hiding this comment.
If you have time, please convert this file to .ts nhe :pepe-cuoi-dam
There was a problem hiding this comment.
convert this to .ts lun nho
There was a problem hiding this comment.
This one to ts lun nho :pepe-cuoi-guong. it's short btw
| */ | ||
| constructor ({ | ||
| name, alias, note, fields = [], indexes = [], checks = [], schema = {}, token, headerColor, noteToken = null, partials = [], | ||
| name, alias, note, fields = [], indexes = [], checks = [], schema = {}, token, headerColor, noteToken = null, partials = [], metadata, |
There was a problem hiding this comment.
this one metadata doesn't have a default value like {} others? :* Although we use ?? {} below
| note: string; | ||
| noteToken: Token; | ||
| color: Color; | ||
| constructor({ name, token, tables, schema, note, color }: RawTableGroup); |
There was a problem hiding this comment.
No metadata in constructor? 🤔
|
|
||
| // Programs that can both (a) reach this metadata's declaration file and | ||
| // (b) see ALL the given target symbols in their nested schema. | ||
| reachableOwners (compiler: Compiler, targets: NodeSymbol[]): NodeSymbol[] { |
There was a problem hiding this comment.
This name is a bit hard to distinguished with owners :*
| const targetNode = nameNode instanceof InfixExpressionNode && nameNode.rightExpression | ||
| ? nameNode.rightExpression | ||
| : nameNode; |
There was a problem hiding this comment.
We can use getRightmostVariable here 🤔
| // qualified `targetName` together identify the target). Hence no alias/settings. | ||
| // e.g. Metadata Table public.users { owner: 'scott' } | ||
| // e.g. Metadata Column public.users.id { pii: true } | ||
| export class MetadataDeclarationNode extends SyntaxNode { |
There was a problem hiding this comment.
Consider merging with ElementDeclarationNode nho :3
SyntaxNodes are meant to group structurally similar nodes with similar roles. At least that's our design
| getTargetKind (): MetadataTargetKind | undefined { | ||
| const value = this.targetKind?.value?.toLowerCase(); | ||
| if (value === undefined) return undefined; | ||
| return ALLOWED_METADATA_TARGET_KINDS.find((k) => k === value); |
There was a problem hiding this comment.
Reconsider METADATA_TARGET_KIND to not include schema? 👀
| // Intermediate, per-block interpreted form of a Metadata declaration. NOT part | ||
| // of the emitted Database: the interpreter merges every block targeting the same | ||
| // element and attaches the merged `values` onto that element's `metadata` field | ||
| // (Table/Column/TableGroup/Note). This shape only lives inside the metadata pass. | ||
| export interface MetadataElement { | ||
| target: { | ||
| kind: MetadataTargetKind; | ||
| name: string[]; | ||
| }; | ||
| valueWithTokens: Record<string, { value: string; token: TokenPosition }>; | ||
| token: TokenPosition; | ||
| } | ||
|
|
There was a problem hiding this comment.
schemaJson is meant for consumer-visible only types only 👀
| private useSpecifier (): UseSpecifierNode { | ||
| const args: { | ||
| importKind?: SyntaxToken; | ||
| subKind?: SyntaxToken; |
| } | ||
|
|
||
| // consume the qualified target name (e.g. `public.users`) | ||
| if (!this.check(SyntaxTokenKind.COLON, SyntaxTokenKind.LBRACE, SyntaxTokenKind.LBRACKET)) { |
There was a problem hiding this comment.
Would this cause parse errors:
Metadata Table t [...] {}
^^^
| return membersList.find((m: NodeSymbol) => m instanceof SchemaSymbol && m.isPublicSchema()); | ||
| } | ||
|
|
||
| export function getGlobalSymbol (compiler: Compiler, filepath: Filepath): NodeSymbol | undefined { |
There was a problem hiding this comment.
maybe getProgramSymbol is a better name, maybe we can tighten the return type?
I think this can be reused in reachableOwners
6049528 to
b317acb
Compare
| } | ||
|
|
||
| private validateSettingList (settingList?: ListExpressionNode): CompileError[] { | ||
| const aggReport = aggregateSettingList(settingList); |
There was a problem hiding this comment.
help me migrate this function to use the below validate helper function lun nho :3
| return [ | ||
| new CompileError( | ||
| CompileErrorCode.INVALID_NAME, | ||
| 'A Metadata target\'s name must be a schema-qualified name', |
There was a problem hiding this comment.
Must be a schema-qualified name? 🤔
| return [ | ||
| new CompileError( | ||
| CompileErrorCode.INVALID_NAME, | ||
| 'Invalid array as Metadata target\'s name.', |
There was a problem hiding this comment.
The point of this was to catch user's accidental errors like Metadata Table name[setting] {}. Can lookup the copywriting in other elements 👀
| // Only validate the value when a real callee is present. When a key has | ||
| // no value the parser emits INVALID_OPERAND via error recovery and | ||
| // synthesises a FunctionApplicationNode whose callee is an EmptyNode — | ||
| // we must not pile on with a second INVALID_METADATA_FIELD in that case. |
There was a problem hiding this comment.
Shorter comment pls :3 Something like "Metadata's simple body without a field is already caught by the parser, so validator skips this case"
| // A key that names a builtin setting for this target kind is validated by | ||
| // the target element's own spec (it will be written onto the typed field). | ||
| // Color-/note-named keys on a target that does NOT support them are absent | ||
| // from the map and fall through to generic scalar validation, staying as | ||
| // custom metadata. The write pass routes through the same per-kind maps, so | ||
| // validation and writing agree by construction. | ||
| // `key` is a free-form lowercased string; a non-builtin key simply misses | ||
| // the map (undefined) and falls through to generic validation below. |
There was a problem hiding this comment.
:V make this more digestible pls. What do we need to be aware of?
| SymbolKind.Column, | ||
| ], | ||
| [MetadataTargetKind.TableGroup]: [ | ||
| SymbolKind.Schema, |
There was a problem hiding this comment.
:V I dont think table group support schema
| SymbolKind.TableGroup, | ||
| ], | ||
| [MetadataTargetKind.Note]: [ | ||
| SymbolKind.Schema, |
There was a problem hiding this comment.
Note also doesnt support schema 👀
| if (meta instanceof MetadataElementMetadata) { | ||
| // Unresolved targets already raise BINDING_ERROR at bind time; there | ||
| // is no element to attach to, so skip them here. | ||
| const targetSymbol = meta.target(this.compiler); |
There was a problem hiding this comment.
possibly can we have a dedicated function for this custom metadata
| // A single builtin metadata field, bundling validation (used by both the inline | ||
| // setting-list path and the metadata-block path) and the dumb-writer assign | ||
| // (used only in the interpret pass to promote block-form values onto typed | ||
| // fields). Both fields are required so that validate/assign key parity is | ||
| // structural — impossible to violate. |
There was a problem hiding this comment.
Can we make this comment more concise :V
| token: Token; | ||
| } | ||
|
|
||
| export type Metadata = CustomMetadata; |
There was a problem hiding this comment.
Why not just re-export the type :* too many names cause confusion
| expect(locations[0].range.startLineNumber).toBe(1); | ||
| }); | ||
|
|
||
| // TODO(metadata): METADATA_TARGET_NOT_FOUND is raised by the binder, but |
8bbd6a6 to
df6944d
Compare
aeea30d to
4b6eed4
Compare
Summary
Issue
(issue link here)
Lasting Changes (Technical)
(please list down: code changes/things that have wide-effect; new libraries/functions added that can be used by others; examples below)
class EmailValidatorto validate email address' validity)Tenant#is_trial?check)Checklist
Please check directly on the box once each of these are done