Skip to content

Commit 886b0fa

Browse files
committed
codegen: Set non-nullable values in constructor with zero/empty values
This is being done so that developers don't have issues with accessing a non-nullable value and it being `null`, that causes a runtime error.
1 parent 1cae861 commit 886b0fa

File tree

4 files changed

+93
-20
lines changed

4 files changed

+93
-20
lines changed

src/codegen/schema.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ module.exports = class SchemaCodeGenerator {
5555
let klass = tsCodegen.klass(name, { export: true, extends: 'Entity' })
5656

5757
// Generate and add a constructor
58-
klass.addMethod(this._generateConstructor(name))
58+
klass.addMethod(this._generateConstructor(name, def.get('fields')))
5959

6060
// Generate and add save() and getById() methods
6161
this._generateStoreMethods(name).forEach(method => klass.addMethod(method))
@@ -72,14 +72,39 @@ module.exports = class SchemaCodeGenerator {
7272
return klass
7373
}
7474

75-
_generateConstructor(entityName) {
75+
// Fields that are non-nullable get an empty/zero value set in the class constructor.
76+
_generateDefaultFieldValues(fields) {
77+
const indexOfIdField = fields.findIndex(field => field.getIn(['name', 'value']) === 'id')
78+
const fieldsWithoutId = fields.remove(indexOfIdField)
79+
80+
const fieldsSetCalls = fieldsWithoutId
81+
.map(field => {
82+
const name = field.getIn(['name', 'value'])
83+
const type = this._typeFromGraphQl(field.get('type'))
84+
const isNullable = type instanceof tsCodegen.NullableType
85+
86+
return { name, type, isNullable }
87+
})
88+
.filter(({ isNullable }) => !isNullable)
89+
.map(({ name, type, isNullable }) => {
90+
const fieldTypeString = isNullable ? type.inner.toString() : type.toString()
91+
92+
return `
93+
this.set('${name}', ${typesCodegen.initializedValueFromAsc(fieldTypeString)})`
94+
})
95+
96+
return fieldsSetCalls.join('')
97+
}
98+
99+
_generateConstructor(entityName, fields) {
76100
return tsCodegen.method(
77101
'constructor',
78102
[tsCodegen.param('id', tsCodegen.namedType('string'))],
79103
undefined,
80104
`
81105
super()
82106
this.set('id', Value.fromString(id))
107+
${this._generateDefaultFieldValues(fields)}
83108
`,
84109
)
85110
}

src/codegen/types/conversions.js

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -188,27 +188,28 @@ const VALUE_TO_ASSEMBLYSCRIPT = [
188188
const ASSEMBLYSCRIPT_TO_VALUE = [
189189
// Arrays
190190

191-
['Array<Address>', '[Bytes]', code => `Value.fromBytesArray(${code})`],
192-
['Array<Bytes>', '[Bytes]', code => `Value.fromBytesArray(${code})`],
193-
['Array<boolean>', '[Boolean]', code => `Value.fromBooleanArray(${code})`],
194-
['Array<i32>', '[Int]', code => `Value.fromI32Array(${code})`],
195-
['Array<BigInt>', '[BigInt]', code => `Value.fromBigIntArray(${code})`],
196-
['Array<string>', '[String]', code => `Value.fromStringArray(${code})`],
197-
['Array<string>', '[ID]', code => `Value.fromStringArray(${code})`],
198-
['Array<BigDecimal>', '[BigDecimal]', code => `Value.fromBigDecimalArray(${code})`],
199-
['Array<string>', /\[.*\]/, code => `Value.fromStringArray(${code})`],
191+
['Array<Address>', '[Bytes]', code => `Value.fromBytesArray(${code})`, 'new Array(0)'],
192+
['Array<Bytes>', '[Bytes]', code => `Value.fromBytesArray(${code})`, 'new Array(0)'],
193+
['Array<boolean>', '[Boolean]', code => `Value.fromBooleanArray(${code})`, 'new Array(0)'],
194+
['Array<i32>', '[Int]', code => `Value.fromI32Array(${code})`, 'new Array(0)'],
195+
['Array<BigInt>', '[BigInt]', code => `Value.fromBigIntArray(${code})`, 'new Array(0)'],
196+
['Array<string>', '[String]', code => `Value.fromStringArray(${code})`, 'new Array(0)'],
197+
['Array<string>', '[ID]', code => `Value.fromStringArray(${code})`, 'new Array(0)'],
198+
['Array<BigDecimal>', '[BigDecimal]', code => `Value.fromBigDecimalArray(${code})`, 'new Array(0)'],
199+
['Array<string>', /\[.*\]/, code => `Value.fromStringArray(${code})`, 'new Array(0)'],
200+
['Array<string | null>', null, code => `Value.fromStringArray(${code})`, 'new Array(0)'],
200201

201202
// Scalar values
202203

203-
['Address', 'Bytes', code => `Value.fromBytes(${code})`],
204-
['Bytes', 'Bytes', code => `Value.fromBytes(${code})`],
205-
['boolean', 'Boolean', code => `Value.fromBoolean(${code})`],
206-
['i32', 'Int', code => `Value.fromI32(${code})`],
207-
['BigInt', 'BigInt', code => `Value.fromBigInt(${code})`],
208-
['string', 'String', code => `Value.fromString(${code})`],
209-
['string', 'ID', code => `Value.fromString(${code})`],
210-
['BigDecimal', 'BigDecimal', code => `Value.fromBigDecimal(${code})`],
211-
['string', /.*/, code => `Value.fromString(${code})`],
204+
['Address', 'Bytes', code => `Value.fromBytes(${code})`, 'Address.zero()'],
205+
['Bytes', 'Bytes', code => `Value.fromBytes(${code})`, 'Bytes.empty()'],
206+
['boolean', 'Boolean', code => `Value.fromBoolean(${code})`, 'false'],
207+
['i32', 'Int', code => `Value.fromI32(${code})`, '0'],
208+
['BigInt', 'BigInt', code => `Value.fromBigInt(${code})`, 'BigInt.zero()'],
209+
['string', 'String', code => `Value.fromString(${code})`, "''"],
210+
['string', 'ID', code => `Value.fromString(${code})`, "''"],
211+
['BigDecimal', 'BigDecimal', code => `Value.fromBigDecimal(${code})`, 'BigDecimal.zero()'],
212+
['string', /.*/, code => `Value.fromString(${code})`, "''"],
212213
]
213214

214215
/**

src/codegen/types/index.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ const findConversionToType = (fromTypeSystem, toTypeSystem, toType) => {
6666
return objectifyConversion(fromTypeSystem, toTypeSystem, conversion)
6767
}
6868

69+
const findInitializationForType = (fromTypeSystem, toTypeSystem, ascType) => {
70+
const conversions = conversionsForTypeSystems(fromTypeSystem, toTypeSystem)
71+
72+
const conversion = conversions.find(conversion =>
73+
typeof conversion.get(0) === 'string'
74+
? conversion.get(0) === ascType
75+
: ascType.match(conversion.get(0)),
76+
)
77+
78+
if (conversion === undefined) {
79+
throw new Error(
80+
`Conversion from '${fromTypeSystem}' to '${toTypeSystem}' for ` +
81+
`target type '${ascType}' is not supported`,
82+
)
83+
}
84+
85+
const conversionObj = objectifyConversion(fromTypeSystem, toTypeSystem, conversion)
86+
87+
return conversionObj.get('convert')(conversion.get(3))
88+
}
89+
6990
// High-level type system API
7091

7192
const ascTypeForEthereum = ethereumType =>
@@ -95,6 +116,9 @@ const valueToAsc = (code, valueType) =>
95116
const valueFromAsc = (code, valueType) =>
96117
findConversionToType('AssemblyScript', 'Value', valueType).get('convert')(code)
97118

119+
const initializedValueFromAsc = ascType =>
120+
findInitializationForType('AssemblyScript', 'Value', ascType)
121+
98122
module.exports = {
99123
// ethereum <-> AssemblyScript
100124
ascTypeForEthereum,
@@ -107,4 +131,5 @@ module.exports = {
107131
valueTypeForAsc,
108132
valueToAsc,
109133
valueFromAsc,
134+
initializedValueFromAsc,
110135
}

src/codegen/types/index.test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,4 +449,26 @@ describe('AssemblyScript -> Value', () => {
449449
expect(codegen.valueFromAsc('x', '[String]')).toBe('Value.fromStringArray(x)')
450450
expect(codegen.valueTypeForAsc('Array<string>')).toBe('[String]')
451451
})
452+
453+
describe('Initialization for zero/empty values', () => {
454+
test('Array<string>', () => {
455+
expect(codegen.initializedValueFromAsc('Array<string>')).toBe('Value.fromStringArray(new Array(0))')
456+
})
457+
458+
test('Array<string | null>', () => {
459+
expect(codegen.initializedValueFromAsc('Array<string | null>')).toBe('Value.fromStringArray(new Array(0))')
460+
})
461+
462+
test('i32', () => {
463+
expect(codegen.initializedValueFromAsc('i32')).toBe('Value.fromI32(0)')
464+
})
465+
466+
test('string', () => {
467+
expect(codegen.initializedValueFromAsc('string')).toBe("Value.fromString('')")
468+
})
469+
470+
test('BigInt', () => {
471+
expect(codegen.initializedValueFromAsc('BigInt')).toBe('Value.fromBigInt(BigInt.zero())')
472+
})
473+
})
452474
})

0 commit comments

Comments
 (0)