@prisma-next/sql-orm-lane 0.3.0-dev.2 → 0.3.0-dev.20

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 (83) hide show
  1. package/README.md +2 -2
  2. package/dist/exports/orm.d.ts +3 -5
  3. package/dist/exports/orm.d.ts.map +1 -0
  4. package/dist/index.d.ts +4 -42
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/mutations/delete-builder.d.ts +9 -0
  7. package/dist/mutations/delete-builder.d.ts.map +1 -0
  8. package/dist/mutations/insert-builder.d.ts +7 -0
  9. package/dist/mutations/insert-builder.d.ts.map +1 -0
  10. package/dist/mutations/update-builder.d.ts +9 -0
  11. package/dist/mutations/update-builder.d.ts.map +1 -0
  12. package/dist/orm/builder.d.ts +38 -0
  13. package/dist/orm/builder.d.ts.map +1 -0
  14. package/dist/orm/capabilities.d.ts +3 -0
  15. package/dist/orm/capabilities.d.ts.map +1 -0
  16. package/dist/orm/context.d.ts +5 -0
  17. package/dist/orm/context.d.ts.map +1 -0
  18. package/dist/orm/state.d.ts +45 -0
  19. package/dist/orm/state.d.ts.map +1 -0
  20. package/dist/orm-include-child.d.ts +35 -0
  21. package/dist/orm-include-child.d.ts.map +1 -0
  22. package/dist/orm-relation-filter.d.ts +19 -0
  23. package/dist/orm-relation-filter.d.ts.map +1 -0
  24. package/dist/{orm-DAnGd7z2.d.ts → orm-types.d.ts} +16 -27
  25. package/dist/orm-types.d.ts.map +1 -0
  26. package/dist/orm.d.ts +5 -0
  27. package/dist/orm.d.ts.map +1 -0
  28. package/dist/plan/lowering.d.ts +2 -0
  29. package/dist/plan/lowering.d.ts.map +1 -0
  30. package/dist/plan/plan-assembly.d.ts +24 -0
  31. package/dist/plan/plan-assembly.d.ts.map +1 -0
  32. package/dist/plan/result-typing.d.ts +2 -0
  33. package/dist/plan/result-typing.d.ts.map +1 -0
  34. package/dist/relations/include-plan.d.ts +38 -0
  35. package/dist/relations/include-plan.d.ts.map +1 -0
  36. package/dist/selection/join.d.ts +3 -0
  37. package/dist/selection/join.d.ts.map +1 -0
  38. package/dist/selection/ordering.d.ts +11 -0
  39. package/dist/selection/ordering.d.ts.map +1 -0
  40. package/dist/selection/pagination.d.ts +6 -0
  41. package/dist/selection/pagination.d.ts.map +1 -0
  42. package/dist/selection/predicates.d.ts +10 -0
  43. package/dist/selection/predicates.d.ts.map +1 -0
  44. package/dist/selection/projection.d.ts +28 -0
  45. package/dist/selection/projection.d.ts.map +1 -0
  46. package/dist/selection/select-builder.d.ts +22 -0
  47. package/dist/selection/select-builder.d.ts.map +1 -0
  48. package/dist/types/internal.d.ts +4 -0
  49. package/dist/types/internal.d.ts.map +1 -0
  50. package/dist/utils/ast.d.ts +2 -0
  51. package/dist/utils/ast.d.ts.map +1 -0
  52. package/dist/utils/errors.d.ts +29 -0
  53. package/dist/utils/errors.d.ts.map +1 -0
  54. package/dist/utils/param-descriptor.d.ts +10 -0
  55. package/dist/utils/param-descriptor.d.ts.map +1 -0
  56. package/package.json +18 -19
  57. package/src/exports/orm.ts +12 -0
  58. package/src/index.ts +11 -0
  59. package/src/mutations/delete-builder.ts +87 -0
  60. package/src/mutations/insert-builder.ts +148 -0
  61. package/src/mutations/update-builder.ts +141 -0
  62. package/src/orm/builder.ts +744 -0
  63. package/src/orm/capabilities.ts +14 -0
  64. package/src/orm/context.ts +10 -0
  65. package/src/orm/state.ts +52 -0
  66. package/src/orm-include-child.ts +169 -0
  67. package/src/orm-relation-filter.ts +93 -0
  68. package/src/orm-types.ts +271 -0
  69. package/src/orm.ts +51 -0
  70. package/src/plan/lowering.ts +1 -0
  71. package/src/plan/plan-assembly.ts +297 -0
  72. package/src/plan/result-typing.ts +1 -0
  73. package/src/relations/include-plan.ts +324 -0
  74. package/src/selection/join.ts +13 -0
  75. package/src/selection/ordering.ts +52 -0
  76. package/src/selection/pagination.ts +11 -0
  77. package/src/selection/predicates.ts +120 -0
  78. package/src/selection/projection.ts +136 -0
  79. package/src/selection/select-builder.ts +82 -0
  80. package/src/types/internal.ts +3 -0
  81. package/src/utils/ast.ts +12 -0
  82. package/src/utils/errors.ts +130 -0
  83. package/src/utils/param-descriptor.ts +19 -0
@@ -0,0 +1,120 @@
1
+ import type { ParamDescriptor } from '@prisma-next/contract/types';
2
+ import type { SqlContract, SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
3
+ import type {
4
+ BinaryExpr,
5
+ ColumnRef,
6
+ OperationExpr,
7
+ ParamRef,
8
+ } from '@prisma-next/sql-relational-core/ast';
9
+ import { augmentDescriptorWithColumnMeta } from '@prisma-next/sql-relational-core/plan';
10
+ import type { BinaryBuilder, ParamPlaceholder } from '@prisma-next/sql-relational-core/types';
11
+ import {
12
+ getColumnInfo,
13
+ getColumnMeta,
14
+ getOperationExpr,
15
+ isColumnBuilder,
16
+ isParamPlaceholder,
17
+ } from '@prisma-next/sql-relational-core/utils/guards';
18
+ import { createBinaryExpr, createColumnRef, createParamRef } from '../utils/ast';
19
+ import {
20
+ errorFailedToBuildWhereClause,
21
+ errorMissingParameter,
22
+ errorUnknownTable,
23
+ } from '../utils/errors';
24
+
25
+ export function buildWhereExpr(
26
+ where: BinaryBuilder,
27
+ contract: SqlContract<SqlStorage>,
28
+ paramsMap: Record<string, unknown>,
29
+ descriptors: ParamDescriptor[],
30
+ values: unknown[],
31
+ ): {
32
+ expr: BinaryExpr;
33
+ codecId?: string;
34
+ paramName: string;
35
+ } {
36
+ let leftExpr: ColumnRef | OperationExpr;
37
+ let codecId: string | undefined;
38
+ let rightExpr: ColumnRef | ParamRef;
39
+ let paramName: string;
40
+
41
+ const operationExpr = getOperationExpr(where.left);
42
+ if (operationExpr) {
43
+ leftExpr = operationExpr;
44
+ } else if (isColumnBuilder(where.left)) {
45
+ const { table, column } = getColumnInfo(where.left);
46
+
47
+ const contractTable = contract.storage.tables[table];
48
+ if (!contractTable) {
49
+ errorUnknownTable(table);
50
+ }
51
+
52
+ const columnMeta: StorageColumn | undefined = contractTable.columns[column];
53
+ // If column not found in contract, still build expression but without codecId
54
+ // This allows flexibility when columnMeta is available on the column builder
55
+ if (columnMeta) {
56
+ codecId = columnMeta.codecId;
57
+ }
58
+ leftExpr = createColumnRef(table, column);
59
+ } else {
60
+ errorFailedToBuildWhereClause();
61
+ }
62
+
63
+ // Handle where.right - can be ParamPlaceholder or AnyColumnBuilder
64
+ if (isParamPlaceholder(where.right)) {
65
+ // Handle param placeholder (existing logic)
66
+ const placeholder: ParamPlaceholder = where.right;
67
+ paramName = placeholder.name;
68
+
69
+ if (!Object.hasOwn(paramsMap, paramName)) {
70
+ errorMissingParameter(paramName);
71
+ }
72
+
73
+ const value = paramsMap[paramName];
74
+ const index = values.push(value);
75
+
76
+ // Construct descriptor if where.left is a ColumnBuilder
77
+ if (isColumnBuilder(where.left)) {
78
+ const { table, column } = getColumnInfo(where.left);
79
+ const contractTable = contract.storage.tables[table];
80
+ const columnMeta = contractTable?.columns[column];
81
+ const builderColumnMeta = getColumnMeta(where.left);
82
+
83
+ descriptors.push({
84
+ name: paramName,
85
+ source: 'dsl',
86
+ refs: { table, column },
87
+ ...(typeof builderColumnMeta?.nullable === 'boolean'
88
+ ? { nullable: builderColumnMeta.nullable }
89
+ : {}),
90
+ });
91
+
92
+ augmentDescriptorWithColumnMeta(descriptors, columnMeta);
93
+ }
94
+
95
+ rightExpr = createParamRef(index, paramName);
96
+ } else if (isColumnBuilder(where.right)) {
97
+ // Handle column builder on the right
98
+ const { table, column } = getColumnInfo(where.right);
99
+
100
+ const contractTable = contract.storage.tables[table];
101
+ if (!contractTable) {
102
+ errorUnknownTable(table);
103
+ }
104
+
105
+ // If column not found in contract, still build expression
106
+ // This allows flexibility when columnMeta is available on the column builder
107
+ rightExpr = createColumnRef(table, column);
108
+ // Use a placeholder paramName for column references (not used for params)
109
+ paramName = '';
110
+ } else {
111
+ // where.right is neither ParamPlaceholder nor ColumnBuilder - invalid state
112
+ errorFailedToBuildWhereClause();
113
+ }
114
+
115
+ return {
116
+ expr: createBinaryExpr(where.op, leftExpr, rightExpr),
117
+ ...(codecId ? { codecId } : {}),
118
+ paramName,
119
+ };
120
+ }
@@ -0,0 +1,136 @@
1
+ import type { TableRef } from '@prisma-next/sql-relational-core/ast';
2
+ import type {
3
+ AnyBinaryBuilder,
4
+ AnyColumnBuilder,
5
+ AnyOrderBuilder,
6
+ JoinOnPredicate,
7
+ NestedProjection,
8
+ } from '@prisma-next/sql-relational-core/types';
9
+ import { isColumnBuilder } from '@prisma-next/sql-relational-core/utils/guards';
10
+ import {
11
+ errorAliasCollision,
12
+ errorAliasPathEmpty,
13
+ errorIncludeAliasNotFound,
14
+ errorInvalidProjectionKey,
15
+ errorInvalidProjectionValue,
16
+ errorProjectionEmpty,
17
+ } from '../utils/errors';
18
+
19
+ export interface ProjectionState {
20
+ readonly aliases: string[];
21
+ readonly columns: AnyColumnBuilder[];
22
+ }
23
+
24
+ export type ProjectionInput = Record<string, AnyColumnBuilder | boolean | NestedProjection>;
25
+
26
+ function generateAlias(path: string[]): string {
27
+ if (path.length === 0) {
28
+ errorAliasPathEmpty();
29
+ }
30
+ return path.join('_');
31
+ }
32
+
33
+ export class AliasTracker {
34
+ private readonly aliases = new Set<string>();
35
+ private readonly aliasToPath = new Map<string, string[]>();
36
+
37
+ register(path: string[]): string {
38
+ const alias = generateAlias(path);
39
+ if (this.aliases.has(alias)) {
40
+ const existingPath = this.aliasToPath.get(alias);
41
+ errorAliasCollision(path, alias, existingPath);
42
+ }
43
+ this.aliases.add(alias);
44
+ this.aliasToPath.set(alias, path);
45
+ return alias;
46
+ }
47
+
48
+ getPath(alias: string): string[] | undefined {
49
+ return this.aliasToPath.get(alias);
50
+ }
51
+
52
+ has(alias: string): boolean {
53
+ return this.aliases.has(alias);
54
+ }
55
+ }
56
+
57
+ export function flattenProjection(
58
+ projection: NestedProjection,
59
+ tracker: AliasTracker,
60
+ currentPath: string[] = [],
61
+ ): { aliases: string[]; columns: AnyColumnBuilder[] } {
62
+ const aliases: string[] = [];
63
+ const columns: AnyColumnBuilder[] = [];
64
+
65
+ for (const [key, value] of Object.entries(projection)) {
66
+ const path = [...currentPath, key];
67
+
68
+ if (isColumnBuilder(value)) {
69
+ const alias = tracker.register(path);
70
+ aliases.push(alias);
71
+ columns.push(value);
72
+ } else if (typeof value === 'object' && value !== null) {
73
+ const nested = flattenProjection(value, tracker, path);
74
+ aliases.push(...nested.aliases);
75
+ columns.push(...nested.columns);
76
+ } else {
77
+ errorInvalidProjectionValue(path);
78
+ }
79
+ }
80
+
81
+ return { aliases, columns };
82
+ }
83
+
84
+ export function buildProjectionState(
85
+ _table: TableRef,
86
+ projection: ProjectionInput,
87
+ includes?: ReadonlyArray<{
88
+ readonly alias: string;
89
+ readonly table: TableRef;
90
+ readonly on: JoinOnPredicate;
91
+ readonly childProjection: ProjectionState;
92
+ readonly childWhere?: AnyBinaryBuilder;
93
+ readonly childOrderBy?: AnyOrderBuilder;
94
+ readonly childLimit?: number;
95
+ }>,
96
+ ): ProjectionState {
97
+ const tracker = new AliasTracker();
98
+ const aliases: string[] = [];
99
+ const columns: AnyColumnBuilder[] = [];
100
+
101
+ for (const [key, value] of Object.entries(projection)) {
102
+ if (value === true) {
103
+ const matchingInclude = includes?.find((inc) => inc.alias === key);
104
+ if (!matchingInclude) {
105
+ errorIncludeAliasNotFound(key);
106
+ }
107
+ aliases.push(key);
108
+ columns.push({
109
+ kind: 'column',
110
+ table: matchingInclude.table.name,
111
+ column: '',
112
+ columnMeta: {
113
+ nativeType: 'jsonb',
114
+ codecId: 'core/json@1',
115
+ nullable: true,
116
+ },
117
+ } as AnyColumnBuilder);
118
+ } else if (isColumnBuilder(value)) {
119
+ const alias = tracker.register([key]);
120
+ aliases.push(alias);
121
+ columns.push(value);
122
+ } else if (typeof value === 'object' && value !== null) {
123
+ const nested = flattenProjection(value as NestedProjection, tracker, [key]);
124
+ aliases.push(...nested.aliases);
125
+ columns.push(...nested.columns);
126
+ } else {
127
+ errorInvalidProjectionKey(key);
128
+ }
129
+ }
130
+
131
+ if (aliases.length === 0) {
132
+ errorProjectionEmpty();
133
+ }
134
+
135
+ return { aliases, columns };
136
+ }
@@ -0,0 +1,82 @@
1
+ import type {
2
+ BinaryExpr,
3
+ ColumnRef,
4
+ Direction,
5
+ ExistsExpr,
6
+ IncludeAst,
7
+ IncludeRef,
8
+ OperationExpr,
9
+ SelectAst,
10
+ TableRef,
11
+ } from '@prisma-next/sql-relational-core/ast';
12
+ import type { IncludeState } from '../relations/include-plan';
13
+ import { createColumnRef, createSelectAst, createTableRef } from '../utils/ast';
14
+ import { errorInvalidColumn, errorMissingAlias, errorMissingColumn } from '../utils/errors';
15
+ import type { ProjectionState } from './projection';
16
+
17
+ export function buildProjectionItems(
18
+ projectionState: ProjectionState,
19
+ includesForMeta: ReadonlyArray<IncludeState>,
20
+ ): Array<{ alias: string; expr: ColumnRef | IncludeRef | OperationExpr }> {
21
+ const projectEntries: Array<{ alias: string; expr: ColumnRef | IncludeRef | OperationExpr }> = [];
22
+ for (let i = 0; i < projectionState.aliases.length; i++) {
23
+ const alias = projectionState.aliases[i];
24
+ if (!alias) {
25
+ errorMissingAlias(i);
26
+ }
27
+ const column = projectionState.columns[i];
28
+ if (!column) {
29
+ errorMissingColumn(alias, i);
30
+ }
31
+
32
+ const matchingInclude = includesForMeta.find((inc) => inc.alias === alias);
33
+ if (matchingInclude) {
34
+ projectEntries.push({
35
+ alias,
36
+ expr: { kind: 'includeRef', alias },
37
+ });
38
+ } else {
39
+ const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
40
+ if (operationExpr) {
41
+ projectEntries.push({
42
+ alias,
43
+ expr: operationExpr,
44
+ });
45
+ } else {
46
+ const col = column as { table: string; column: string };
47
+ const tableName = col.table;
48
+ const columnName = col.column;
49
+ if (!tableName || !columnName) {
50
+ errorInvalidColumn(alias, i);
51
+ }
52
+ projectEntries.push({
53
+ alias,
54
+ expr: createColumnRef(tableName, columnName),
55
+ });
56
+ }
57
+ }
58
+ }
59
+ return projectEntries;
60
+ }
61
+
62
+ export function buildSelectAst(params: {
63
+ table: TableRef;
64
+ projectEntries: Array<{ alias: string; expr: ColumnRef | IncludeRef | OperationExpr }>;
65
+ includesAst?: ReadonlyArray<IncludeAst>;
66
+ whereExpr?: BinaryExpr | ExistsExpr;
67
+ orderByClause?: ReadonlyArray<{
68
+ expr: ColumnRef | OperationExpr;
69
+ dir: Direction;
70
+ }>;
71
+ limit?: number;
72
+ }): SelectAst {
73
+ const { table, projectEntries, includesAst, whereExpr, orderByClause, limit } = params;
74
+ return createSelectAst({
75
+ from: createTableRef(table.name),
76
+ project: projectEntries,
77
+ ...(includesAst ? { includes: includesAst } : {}),
78
+ ...(whereExpr ? { where: whereExpr } : {}),
79
+ ...(orderByClause ? { orderBy: orderByClause } : {}),
80
+ ...(limit !== undefined ? { limit } : {}),
81
+ });
82
+ }
@@ -0,0 +1,3 @@
1
+ export type { OrmBuilderState, OrmIncludeState, RelationFilter } from '../orm/state';
2
+ export type { MetaBuildArgs } from '../plan/plan-assembly';
3
+ export type { IncludeState } from '../relations/include-plan';
@@ -0,0 +1,12 @@
1
+ export {
2
+ createBinaryExpr,
3
+ createColumnRef,
4
+ createDeleteAst,
5
+ createInsertAst,
6
+ createJoinOnExpr,
7
+ createOrderByItem,
8
+ createParamRef,
9
+ createSelectAst,
10
+ createTableRef,
11
+ createUpdateAst,
12
+ } from '@prisma-next/sql-relational-core/ast';
@@ -0,0 +1,130 @@
1
+ import { planInvalid } from '@prisma-next/plan';
2
+ import type { StorageColumn } from '@prisma-next/sql-contract/types';
3
+
4
+ export function errorModelNotFound(modelName: string): never {
5
+ throw planInvalid(`Model ${modelName} not found in mappings`);
6
+ }
7
+
8
+ export function errorTableNotFound(tableName: string): never {
9
+ throw planInvalid(`Table ${tableName} not found in schema`);
10
+ }
11
+
12
+ export function errorUnknownTable(tableName: string): never {
13
+ throw planInvalid(`Unknown table ${tableName}`);
14
+ }
15
+
16
+ export function errorUnknownColumn(columnName: string, tableName: string): never {
17
+ throw planInvalid(`Unknown column ${columnName} in table ${tableName}`);
18
+ }
19
+
20
+ export function errorMissingParameter(paramName: string): never {
21
+ throw planInvalid(`Missing value for parameter ${paramName}`);
22
+ }
23
+
24
+ export function errorAliasPathEmpty(): never {
25
+ throw planInvalid('Alias path cannot be empty');
26
+ }
27
+
28
+ export function errorAliasCollision(path: string[], alias: string, existingPath?: string[]): never {
29
+ throw planInvalid(
30
+ `Alias collision: path ${path.join('.')} would generate alias "${alias}" which conflicts with path ${existingPath?.join('.') ?? 'unknown'}`,
31
+ );
32
+ }
33
+
34
+ export function errorInvalidProjectionValue(path: string[]): never {
35
+ throw planInvalid(
36
+ `Invalid projection value at path ${path.join('.')}: expected ColumnBuilder or nested object`,
37
+ );
38
+ }
39
+
40
+ export function errorIncludeAliasNotFound(alias: string): never {
41
+ throw planInvalid(
42
+ `Include alias "${alias}" not found. Did you call includeMany() with alias "${alias}"?`,
43
+ );
44
+ }
45
+
46
+ export function errorInvalidProjectionKey(key: string): never {
47
+ throw planInvalid(
48
+ `Invalid projection value at key "${key}": expected ColumnBuilder, boolean true (for includes), or nested object`,
49
+ );
50
+ }
51
+
52
+ export function errorProjectionEmpty(): never {
53
+ throw planInvalid('select() requires at least one column or include');
54
+ }
55
+
56
+ export function errorCreateRequiresFields(): never {
57
+ throw planInvalid('create() requires at least one field');
58
+ }
59
+
60
+ export function errorUpdateRequiresFields(): never {
61
+ throw planInvalid('update() requires at least one field');
62
+ }
63
+
64
+ export function errorIncludeRequiresCapabilities(): never {
65
+ throw planInvalid('includeMany requires lateral and jsonAgg capabilities');
66
+ }
67
+
68
+ export function errorIncludeCapabilitiesNotTrue(): never {
69
+ throw planInvalid('includeMany requires lateral and jsonAgg capabilities to be true');
70
+ }
71
+
72
+ export function errorMultiColumnJoinsNotSupported(): never {
73
+ throw planInvalid('Multi-column joins in includes are not yet supported');
74
+ }
75
+
76
+ export function errorJoinColumnsMustBeDefined(): never {
77
+ throw planInvalid('Join columns must be defined');
78
+ }
79
+
80
+ export function errorColumnNotFound(columnName: string, tableName: string): never {
81
+ throw planInvalid(`Column ${columnName} not found in table ${tableName}`);
82
+ }
83
+
84
+ export function errorChildProjectionMustBeSpecified(): never {
85
+ throw planInvalid('Child projection must be specified');
86
+ }
87
+
88
+ export function errorChildProjectionEmpty(): never {
89
+ throw planInvalid('Child projection must not be empty after filtering boolean values');
90
+ }
91
+
92
+ export function errorMissingAlias(index: number): never {
93
+ throw planInvalid(`Missing alias at index ${index}`);
94
+ }
95
+
96
+ export function errorMissingColumn(alias: string, index: number): never {
97
+ throw planInvalid(`Missing column for alias "${alias}" at index ${index}`);
98
+ }
99
+
100
+ export function errorInvalidColumn(alias: string, index: number): never {
101
+ throw planInvalid(`Invalid column for alias "${alias}" at index ${index}`);
102
+ }
103
+
104
+ export function errorRelationNotFound(relationName: string, modelName: string): never {
105
+ throw planInvalid(`Relation ${relationName} not found on model ${modelName}`);
106
+ }
107
+
108
+ export function errorFailedToBuildWhereClause(): never {
109
+ throw planInvalid('Failed to build WHERE clause');
110
+ }
111
+
112
+ export function assertColumnExists(
113
+ columnMeta: StorageColumn | undefined,
114
+ columnName: string,
115
+ tableName: string,
116
+ ): asserts columnMeta is StorageColumn {
117
+ if (!columnMeta) {
118
+ errorUnknownColumn(columnName, tableName);
119
+ }
120
+ }
121
+
122
+ export function assertParameterExists(
123
+ paramsMap: Record<string, unknown>,
124
+ paramName: string,
125
+ ): unknown {
126
+ if (!Object.hasOwn(paramsMap, paramName)) {
127
+ errorMissingParameter(paramName);
128
+ }
129
+ return paramsMap[paramName];
130
+ }
@@ -0,0 +1,19 @@
1
+ import type { ParamDescriptor } from '@prisma-next/contract/types';
2
+
3
+ export function createParamDescriptor(args: {
4
+ name: string;
5
+ table: string;
6
+ column: string;
7
+ codecId?: string;
8
+ nativeType?: string;
9
+ nullable: boolean;
10
+ }): ParamDescriptor {
11
+ return {
12
+ name: args.name,
13
+ source: 'dsl',
14
+ refs: { table: args.table, column: args.column },
15
+ ...(args.codecId ? { codecId: args.codecId } : {}),
16
+ ...(args.nativeType ? { nativeType: args.nativeType } : {}),
17
+ nullable: args.nullable,
18
+ };
19
+ }