@balena/abstract-sql-to-typescript
Advanced tools
Comparing version 1.1.0-reverse-references-3805f8e36d11173a85330c6ef23514dcc9dfa863 to 1.1.0-type-helpers-033b23b4738ac777f7ddd65cb61d23289afdc117
@@ -9,3 +9,6 @@ # Change Log | ||
* Add support for reverse references using relationships info [Pagan Gazzard] | ||
* Add type helpers for dealing with expanded/deferred read types [Pagan Gazzard] | ||
## 1.0.3 - 2020-12-30 | ||
* Use the referenced field's data type for foreign keys/concept types [Pagan Gazzard] | ||
@@ -12,0 +15,0 @@ |
@@ -6,2 +6,16 @@ "use strict"; | ||
const common_tags_1 = require("common-tags"); | ||
const typeHelpers = { | ||
read: `\ | ||
export type DateString = string; | ||
export type Expanded<T> = Extract<T, any[]>; | ||
export type PickExpanded<T, U extends keyof T> = { | ||
[P in K]: Expanded<T[P]>; | ||
}; | ||
export type Deferred<T> = Exclude<T, any[]>; | ||
export type PickDeferred<T, U extends keyof T> = { | ||
[P in K]: Deferred<T[P]>; | ||
}; | ||
`, | ||
write: '', | ||
}; | ||
const trimNL = new common_tags_1.TemplateTag(common_tags_1.replaceResultTransformer(/^[\r\n]*|[\r\n]*$/g, '')); | ||
@@ -63,49 +77,24 @@ const modelNameToCamelCaseName = (s) => s | ||
}; | ||
const fieldsToInterfaceProps = (m, fields, opts) => fields.map((f) => { | ||
const fieldsToInterfaceProps = (m, fields, opts) => fields | ||
.map((f) => { | ||
const nullable = f.required ? '' : ' | null'; | ||
return `${odata_to_abstract_sql_1.sqlNameToODataName(f.fieldName)}: ${sqlTypeToTypescriptType(m, f, opts)}${nullable};`; | ||
}); | ||
const recurseRelationships = (m, relationships, opts, currentTable, parentKey) => Object.keys(relationships).flatMap((key) => { | ||
if (key === '$') { | ||
const [localField, referencedField,] = relationships.$; | ||
if (currentTable.idField === localField && referencedField != null) { | ||
const referencedTable = m.tables[referencedField[0]]; | ||
if (referencedTable != null) { | ||
const referencedInterface = modelNameToCamelCaseName(referencedTable.name); | ||
return `${parentKey}?: ${referencedInterface}[];`; | ||
} | ||
} | ||
return []; | ||
} | ||
return recurseRelationships(m, relationships[key], opts, currentTable, `${parentKey}__${key.replace(/ /g, '_')}`); | ||
}); | ||
const relationshipsToInterfaceProps = (m, table, opts) => { | ||
const relationships = m.relationships[table.resourceName]; | ||
if (relationships == null) { | ||
return []; | ||
} | ||
return Object.keys(relationships).flatMap((key) => { | ||
if (key === 'has') { | ||
return []; | ||
} | ||
return recurseRelationships(m, relationships[key], opts, table, key.replace(/ /g, '_')); | ||
}); | ||
}; | ||
const tableToInterface = (m, table, opts) => { | ||
const relationshipProps = opts.mode === 'read' ? relationshipsToInterfaceProps(m, table, opts) : []; | ||
return trimNL ` | ||
${odata_to_abstract_sql_1.sqlNameToODataName(f.fieldName)}: ${sqlTypeToTypescriptType(m, f, opts)}${nullable}; | ||
`; | ||
}) | ||
.join('\n'); | ||
const tableToInterface = (m, table, opts) => trimNL ` | ||
export interface ${modelNameToCamelCaseName(table.name)} { | ||
${[...fieldsToInterfaceProps(m, table.fields, opts), ...relationshipProps].join('\n\t')} | ||
${fieldsToInterfaceProps(m, table.fields, opts)} | ||
} | ||
`; | ||
}; | ||
const abstractSqlToTypescriptTypes = (m, opts = {}) => { | ||
var _a; | ||
const mode = (_a = opts.mode) !== null && _a !== void 0 ? _a : 'read'; | ||
const requiredOptions = { | ||
...opts, | ||
mode: (_a = opts.mode) !== null && _a !== void 0 ? _a : 'read', | ||
mode, | ||
}; | ||
return trimNL ` | ||
export type DateString = string; | ||
${typeHelpers[mode]} | ||
${Object.keys(m.tables) | ||
@@ -112,0 +101,0 @@ .map((tableName) => { |
{ | ||
"name": "@balena/abstract-sql-to-typescript", | ||
"version": "1.1.0-reverse-references-3805f8e36d11173a85330c6ef23514dcc9dfa863", | ||
"version": "1.1.0-type-helpers-033b23b4738ac777f7ddd65cb61d23289afdc117", | ||
"description": "A translator for abstract sql into typescript types.", | ||
@@ -5,0 +5,0 @@ "main": "out/index.js", |
115
src/index.ts
@@ -6,5 +6,2 @@ import { | ||
InNode, | ||
Relationship, | ||
RelationshipInternalNode, | ||
RelationshipLeafNode, | ||
} from '@balena/abstract-sql-compiler'; | ||
@@ -14,2 +11,17 @@ import { sqlNameToODataName } from '@balena/odata-to-abstract-sql'; | ||
const typeHelpers = { | ||
read: `\ | ||
export type DateString = string; | ||
export type Expanded<T> = Extract<T, any[]>; | ||
export type PickExpanded<T, U extends keyof T> = { | ||
[P in K]: Expanded<T[P]>; | ||
}; | ||
export type Deferred<T> = Exclude<T, any[]>; | ||
export type PickDeferred<T, U extends keyof T> = { | ||
[P in K]: Deferred<T[P]>; | ||
}; | ||
`, | ||
write: '', | ||
}; | ||
const trimNL = new TemplateTag( | ||
@@ -99,70 +111,16 @@ replaceResultTransformer(/^[\r\n]*|[\r\n]*$/g, ''), | ||
opts: RequiredOptions, | ||
): string[] => | ||
fields.map((f) => { | ||
const nullable = f.required ? '' : ' | null'; | ||
return `${sqlNameToODataName(f.fieldName)}: ${sqlTypeToTypescriptType( | ||
m, | ||
f, | ||
opts, | ||
)}${nullable};`; | ||
}); | ||
): string => | ||
fields | ||
.map((f) => { | ||
const nullable = f.required ? '' : ' | null'; | ||
return trimNL` | ||
${sqlNameToODataName(f.fieldName)}: ${sqlTypeToTypescriptType( | ||
m, | ||
f, | ||
opts, | ||
)}${nullable}; | ||
`; | ||
}) | ||
.join('\n'); | ||
const recurseRelationships = ( | ||
m: AbstractSqlModel, | ||
relationships: Relationship, | ||
opts: RequiredOptions, | ||
currentTable: AbstractSqlTable, | ||
parentKey: string, | ||
): string[] => | ||
Object.keys(relationships).flatMap((key) => { | ||
if (key === '$') { | ||
const [ | ||
localField, | ||
referencedField, | ||
] = (relationships as RelationshipLeafNode).$; | ||
if (currentTable.idField === localField && referencedField != null) { | ||
const referencedTable = m.tables[referencedField[0]]; | ||
if (referencedTable != null) { | ||
const referencedInterface = modelNameToCamelCaseName( | ||
referencedTable.name, | ||
); | ||
return `${parentKey}?: ${referencedInterface}[];`; | ||
} | ||
} | ||
return []; | ||
} | ||
return recurseRelationships( | ||
m, | ||
(relationships as RelationshipInternalNode)[key], | ||
opts, | ||
currentTable, | ||
`${parentKey}__${key.replace(/ /g, '_')}`, | ||
); | ||
}); | ||
const relationshipsToInterfaceProps = ( | ||
m: AbstractSqlModel, | ||
table: AbstractSqlTable, | ||
opts: RequiredOptions, | ||
): string[] => { | ||
const relationships = m.relationships[table.resourceName]; | ||
if (relationships == null) { | ||
return []; | ||
} | ||
return Object.keys(relationships).flatMap((key) => { | ||
// We skip `has` a the top level as we omit it by convention //, and we skip any | ||
// if (key === 'has' || m.tables[key] != null) { | ||
if (key === 'has') { | ||
return []; | ||
} | ||
return recurseRelationships( | ||
m, | ||
relationships[key], | ||
opts, | ||
table, | ||
key.replace(/ /g, '_'), | ||
); | ||
}); | ||
}; | ||
const tableToInterface = ( | ||
@@ -172,14 +130,7 @@ m: AbstractSqlModel, | ||
opts: RequiredOptions, | ||
) => { | ||
const relationshipProps = | ||
opts.mode === 'read' ? relationshipsToInterfaceProps(m, table, opts) : []; | ||
return trimNL` | ||
) => trimNL` | ||
export interface ${modelNameToCamelCaseName(table.name)} { | ||
${[...fieldsToInterfaceProps(m, table.fields, opts), ...relationshipProps].join( | ||
'\n\t', | ||
)} | ||
${fieldsToInterfaceProps(m, table.fields, opts)} | ||
} | ||
`; | ||
}; | ||
@@ -195,9 +146,9 @@ export interface Options { | ||
): string => { | ||
const mode = opts.mode ?? 'read'; | ||
const requiredOptions: RequiredOptions = { | ||
...opts, | ||
mode: opts.mode ?? 'read', | ||
mode, | ||
}; | ||
return trimNL` | ||
export type DateString = string; | ||
${typeHelpers[mode]} | ||
${Object.keys(m.tables) | ||
@@ -204,0 +155,0 @@ .map((tableName) => { |
@@ -21,8 +21,21 @@ import { AbstractSqlModel } from '@balena/abstract-sql-compiler'; | ||
}; | ||
const result = abstractSqlToTypescriptTypes(t, { mode }); | ||
expect(abstractSqlToTypescriptTypes(t, { mode })).to.equal(source` | ||
if (mode == null || mode === 'read') { | ||
expect(result).to.equal(source` | ||
export type DateString = string; | ||
export type Expanded<T> = Extract<T, any[]>; | ||
export type PickExpanded<T, U extends keyof T> = { | ||
[P in K]: Expanded<T[P]>; | ||
}; | ||
export type Deferred<T> = Exclude<T, any[]>; | ||
export type PickDeferred<T, U extends keyof T> = { | ||
[P in K]: Deferred<T[P]>; | ||
}; | ||
${expectation} | ||
`); | ||
} else { | ||
expect(result).to.equal(expectation); | ||
} | ||
}); | ||
@@ -159,33 +172,2 @@ }; | ||
}, | ||
relationships: { | ||
test: { | ||
parent: { | ||
$: ['parent', ['parent', 'id']], | ||
}, | ||
has: { | ||
parent: { | ||
$: ['parent', ['parent', 'id']], | ||
}, | ||
}, | ||
references: { | ||
other: { | ||
$: ['references-other', ['other', 'id']], | ||
}, | ||
}, | ||
test: { | ||
references: { | ||
other: { | ||
$: ['id', ['test-references-other', 'test']], | ||
}, | ||
}, | ||
}, | ||
}, | ||
other: { | ||
'is referenced by': { | ||
test: { | ||
$: ['id', ['test', 'references-other']], | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; | ||
@@ -207,3 +189,2 @@ | ||
id: number; | ||
is_referenced_by__test?: Test[]; | ||
} | ||
@@ -210,0 +191,0 @@ |
@@ -13,3 +13,3 @@ { | ||
"skipLibCheck": true, | ||
"target": "es2019", | ||
"target": "es2018", | ||
"outDir": "out", | ||
@@ -16,0 +16,0 @@ "resolveJsonModule": true |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
19874
496