First thing. This bad form because there significant differences between 0.5.0x and 0.8.3. You should be giving an indication of the range that actually compiles and works, or even better, just declare the compiler you are using like:
pragma solidity 0.8.3;
Since this is using elements of the formerly "experimental ABI" there is no doubt the code does not compile with 0.7.6 or lower without modification to the code.
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.3;
contract Nested {
struct Record {
string id;
uint requestTime;
uint releaseTime;
Direction dir;
}
struct Direction {
bool foo;
uint bar;
}
mapping(address => Record[]) records;
function insert(address key, string memory id, uint requestTime, uint releaseTime, bool foo, uint bar) public {
Direction memory d = Direction({
foo: foo,
bar: bar
});
Record memory r = Record({
id: id,
requestTime: requestTime,
releaseTime: releaseTime,
dir: d
});
records[key].push(r);
}
function inspect(address key) public view returns(Record[] memory) {
return records[key];
}
}
You probably found that you can't just add public
to the mapping.
You might get something like:
call to Nested.records errored: Error encoding arguments: Error: invalid BigNumber string (argument="value", value="", code=INVALID_ARGUMENT, version=bignumber/5.0.8)
I found it a little disconcerting that some iterations of my experiment appeared to compile successfully and then generated that error at runtime. IMHO, it would be better if the compiler rejected the source code unless a reliable view function can be constructed - a good reminder to beware of hidden dangers when relying on leading-edge compiler features.
A more traditional and possibly more efficient approach would be to present several fixed-length ABI functions, along these lines:
function inspectLength(address key) public view returns(uint) {
return records[key].length;
}
function inspectRecord(address key, uint record) public view returns(Record memory) {
return records[key][record];
}
That pushes the interaction concern to the clients. They can inspect individual records or enumerate them all and there is no need to fetch an entire array when most of its values have been seen before.
Aside from a little extra deployment cost owing to contract size, a case could be made for including both approaches - get all and get one.
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.0;
contract Nested {
struct Record {
string id;
uint requestTime;
uint releaseTime;
Direction dir;
}
struct Direction {
bool foo;
uint bar;
}
mapping(address => Record[]) records;
function insert(address key, string memory id, uint requestTime, uint releaseTime, bool foo, uint bar) public {
Direction memory d = Direction({
foo: foo,
bar: bar
});
Record memory r = Record({
id: id,
requestTime: requestTime,
releaseTime: releaseTime,
dir: d
});
records[key].push(r);
}
function inspect(address key) public view returns(Record[] memory) {
return records[key];
}
function inspectLength(address key) public view returns(uint) {
return records[key].length;
}
function inspectRecord(address key, uint record) public view returns(Record memory) {
return records[key][record];
}
}
Hope it helps.