Skip to content

Commit

Permalink
cds.BinaryBuffer, cds.LargeBinaryReadable (#489)
Browse files Browse the repository at this point in the history
Fixes #483
  • Loading branch information
daogrady authored Feb 7, 2025
1 parent 72b8483 commit e3dd217
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
- Introduce `cds.env.typer.build_task` to allow disabling the `typescript` build task shipped with cds-typer by setting it to `false`

### Changed
- [breaking] The types `cds.Binary` and `cds.LargeBinary` are now generated as `Buffer` and `Readable` respectively to reflect the behaviour of the new database packages `@cap-js/hana` and `@cap-js/sqlite`. You can switch back to the old behaviour by adding `legacy_binary_types: true` to your project configuration.
- `CHANGELOG.md` and `LICENSE` files are no longer part of the npm package.

### Deprecated
Expand Down
4 changes: 4 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ const flags = enrichFlagSchema({
desc: `If set to true, floating point properties are generated${EOL}as IEEE754 compatible '(number | string)' instead of 'number'.`,
default: 'false'
}),
legacyBinaryTypes: parameterTypes.boolean({
desc: `If set to true, Binary and LargeBinary are generated${EOL}as strings.`,
default: 'false'
}),
targetModuleType: {
desc: `Output format for generated .js files.${EOL}Setting it to auto tries to derive the module type from${EOL}the package.json and falls back to CJS.`,
allowed: ['esm', 'cjs', 'auto'],
Expand Down
11 changes: 8 additions & 3 deletions lib/resolution/builtin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ class BuiltinResolver {
#builtins = {
UUID: 'string',
String: 'string',
Binary: 'string',
Binary: 'Buffer',
LargeString: 'string',
LargeBinary: 'Buffer | string | {value: import("stream").Readable, $mediaContentType: string, $mediaContentDispositionFilename?: string, $mediaContentDispositionType?: string}',
LargeBinary: 'import("stream").Readable',
Vector: 'string',
Integer: 'number',
UInt8: 'number',
Expand All @@ -35,14 +35,19 @@ class BuiltinResolver {
/**
* @param {object} options - additional resolution options
* @param {boolean} [options.IEEE754Compatible] - if true, the Decimal, DecimalFloat, Float, and Double types are also allowed to be strings
* @param {boolean} [options.legacyBinaryTypes] - if true, the Binary and LargeBinary types are strings
*/
constructor ({ IEEE754Compatible } = {}) {
constructor ({ IEEE754Compatible, legacyBinaryTypes } = {}) {
if (IEEE754Compatible) {
this.#builtins.Decimal = '(number | string)'
this.#builtins.DecimalFloat = '(number | string)'
this.#builtins.Float = '(number | string)'
this.#builtins.Double = '(number | string)'
}
if (legacyBinaryTypes) {
this.#builtins.Binary = 'string'
this.#builtins.LargeBinary = 'Buffer | string | {value: import("stream").Readable, $mediaContentType: string, $mediaContentDispositionFilename?: string, $mediaContentDispositionType?: string}'
}
this.#builtins = Object.freeze(this.#builtins)
}

Expand Down
2 changes: 1 addition & 1 deletion lib/resolution/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Resolver {
this.visitor = visitor

/** @type {BuiltinResolver} */
this.builtinResolver = new BuiltinResolver({ IEEE754Compatible: configuration.IEEE754Compatible })
this.builtinResolver = new BuiltinResolver({ IEEE754Compatible: configuration.IEEE754Compatible, legacyBinaryTypes: configuration.legacyBinaryTypes })

/** @type {Library[]} */
this.libraries = [new Library(require.resolve('../../library/cds.hana.ts'))]
Expand Down
4 changes: 4 additions & 0 deletions lib/typedefs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ export module config {
*/
IEEE754Compatible: boolean
targetModuleType: 'cjs' | 'esm' | 'auto'
/**
* `legacyBinaryTypes = true` -> Binary and LargeBinary are generated as `string` and a union type respectively
*/
legacyBinaryTypes: boolean
}
}

Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@
"description": "If set to true, floating point properties are generated\nas IEEE754 compatible '(number | string)' instead of 'number'.",
"default": false
},
"legacy_binary_types": {
"type": "boolean",
"description": "If set to true, Binary and LargeBinary are generated\nas strings.",
"default": false
},
"target_module_type": {
"type": "string",
"description": "Output format for generated .js files.\nSetting it to auto tries to derive the module type from\nthe package.json and falls back to CJS.",
Expand Down
35 changes: 14 additions & 21 deletions test/unit/output.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,14 @@ describe('Compilation Tests', () => {
})

describe('Builtin Types Tests', () => {
it('should verify primitive types', async () => {
it('should verify primitive types with default settings', async () => {
const astw = (await prepareUnitTest('builtins/model.cds', locations.testOutput('output_test/builtin'))).astw
assert.ok(astw.exists('_EAspect', 'uuid', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'str', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'bin', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'bin', m => check.isNullable(m.type, [st => check.isTypeReference(st, 'Buffer') ])))
// assert.ok(astw.exists('_EAspect', 'vec', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'lstr', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'lbin', m => check.isUnionType(m.type, [
st => st.full === 'Buffer',
check.isString
])))
assert.ok(astw.exists('_EAspect', 'lbin', m => check.isUnionType(m.type, [check.isLiteral]))) // is actually more complex, but the import('stream').Readable is not feasibly pulled from the AST
assert.ok(astw.exists('_EAspect', 'integ', m => check.isNullable(m.type, [check.isNumber])))
assert.ok(astw.exists('_EAspect', 'uint8', m => check.isNullable(m.type, [check.isNumber])))
assert.ok(astw.exists('_EAspect', 'int16', m => check.isNullable(m.type, [check.isNumber])))
Expand All @@ -132,19 +129,9 @@ describe('Compilation Tests', () => {

it('should verify IEEE754 types', async () => {
const ieee754 = m => check.isParenthesizedType(m, st => check.isUnionType(st, [check.isNumber, check.isString]))

const astw = (await prepareUnitTest('builtins/model.cds', locations.testOutput('output_test/builtin'), {
typerOptions: { IEEE754Compatible: true }
})).astw
assert.ok(astw.exists('_EAspect', 'uuid', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'str', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'bin', m => check.isNullable(m.type, [check.isString])))
// assert.ok(astw.exists('_EAspect', 'vec', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'lstr', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'lbin', m => check.isUnionType(m.type, [
st => st.full === 'Buffer',
check.isString
])))
assert.ok(astw.exists('_EAspect', 'integ', m => check.isNullable(m.type, [check.isNumber])))
assert.ok(astw.exists('_EAspect', 'uint8', m => check.isNullable(m.type, [check.isNumber])))
assert.ok(astw.exists('_EAspect', 'int16', m => check.isNullable(m.type, [check.isNumber])))
Expand All @@ -153,11 +140,17 @@ describe('Compilation Tests', () => {
assert.ok(astw.exists('_EAspect', 'integer64', m => check.isNullable(m.type, [check.isNumber])))
assert.ok(astw.exists('_EAspect', 'dec', m => check.isNullable(m.type, [ieee754])))
assert.ok(astw.exists('_EAspect', 'doub', m => check.isNullable(m.type, [ieee754])))
assert.ok(astw.exists('_EAspect', 'd', m => check.isNullable(m.type, [st => check.isTypeReference(st, '___.CdsDate')])))
assert.ok(astw.exists('_EAspect', 't', m => check.isNullable(m.type, [st => check.isTypeReference(st, '___.CdsTime')])))
assert.ok(astw.exists('_EAspect', 'dt', m => check.isNullable(m.type, [st => check.isTypeReference(st, '___.CdsDateTime')])))
assert.ok(astw.exists('_EAspect', 'ts', m => check.isNullable(m.type, [st => check.isTypeReference(st, '___.CdsTimestamp')])))
assert.ok(astw.exists('_EAspect', 'map', m => check.isNullable(m.type, [st => check.isTypeReference(st, '___.CdsMap')])))
})

it('should verify legacy binary types', async () => {
const astw = (await prepareUnitTest('builtins/model.cds', locations.testOutput('output_test/builtin'), {
typerOptions: { legacyBinaryTypes: true }
})).astw
assert.ok(astw.exists('_EAspect', 'bin', m => check.isNullable(m.type, [check.isString])))
assert.ok(astw.exists('_EAspect', 'lbin', m => check.isUnionType(m.type, [
st => st.full === 'Buffer',
check.isString
])))
})
})

Expand Down

0 comments on commit e3dd217

Please sign in to comment.