@patchworkdev/pdk
Version:
Patchwork Development Kit
431 lines (429 loc) • 16.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateSchemaFile = generateSchemaFile;
const _ = __importStar(require("lodash"));
const config_1 = require("../../../common/helpers/config");
const file_1 = require("../../../common/helpers/file");
const logger_1 = require("../../../common/helpers/logger");
async function generateSchemaFile(projectConfig, outputFile) {
logger_1.logger.debug(`Attempting to generate ponder schema at ${outputFile}`);
const coreEnums = coreEnumStructure();
const coreTables = coreTableStructure();
const contractTables = getUserContractTableStructure(projectConfig);
const schemaFile = renderSchemaFile(coreEnums, {
...coreTables,
...contractTables,
});
await (0, file_1.formatAndSaveFile)(outputFile, schemaFile);
}
function coreEnumStructure() {
const enums = {
PatchType: ['PATCH', 'ERC1155', 'ACCOUNT'],
LogType: ['ADD', 'REMOVE'],
FeeChangeType: ['PROPOSE', 'COMMIT'],
AssignType: ['ASSIGN', 'UNASSIGN'],
SchemaTypes: [
'BOOLEAN',
'INT8',
'INT16',
'INT32',
'INT64',
'INT128',
'INT256',
'UINT8',
'UINT16',
'UINT32',
'UINT64',
'UINT128',
'UINT256',
'CHAR8',
'CHAR16',
'CHAR32',
'CHAR64',
'LITEREF',
'ADDRESS',
'STRING',
],
};
return enums;
}
function coreTableStructure() {
const tables = {
Chain: {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: 'name', value: 'p.text().notNull()' },
{ key: 'namespace', value: 'p.text().notNull()' },
{ key: 'patchworkAddress', value: 'p.hex().notNull()' },
{ key: 'timestamp', value: 'p.bigint().notNull()' },
],
relations: {
block: {
type: 'many',
table: 'block',
name: 'block',
relationName: 'chainId',
},
},
},
Block: {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: 'extraData', value: 'p.hex().notNull()' },
{ key: 'number', value: 'p.bigint().notNull()' },
{ key: 'timestamp', value: 'p.bigint().notNull()' },
{ key: 'chainId', value: 'p.text().notNull()' },
],
relations: {
chain: {
type: 'one',
name: 'chain',
table: 'chain',
fields: ['chainId'],
references: ['id'],
},
},
},
Tx: {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: 'blockId', value: 'p.text().notNull()' },
{ key: 'timestamp', value: 'p.bigint().notNull()' },
{ key: 'fromId', value: 'p.text().notNull()' },
{ key: 'nonce', value: 'p.integer().notNull()' },
{ key: 'toId', value: 'p.text()' },
{ key: 'txIndex', value: 'p.integer().notNull()' },
{ key: 'value', value: 'p.bigint().notNull()' },
{ key: 'chainId', value: 'p.text().notNull()' },
],
relations: {
block: {
type: 'one',
name: 'block',
table: 'block',
fields: ['blockId'],
references: ['id'],
},
from: {
type: 'one',
name: 'from',
table: 'address',
fields: ['fromId'],
references: ['id'],
},
to: {
type: 'one',
name: 'to',
table: 'address',
fields: ['toId'],
references: ['id'],
},
chain: {
type: 'one',
name: 'chain',
table: 'chain',
fields: ['chainId'],
references: ['id'],
},
},
},
GlobalAddress: {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: 'address', value: 'p.hex().notNull()' },
{ key: 'timestamp', value: 'p.bigint().notNull()' },
],
relations: {
address: {
type: 'many',
name: 'address',
table: 'address',
relationName: 'addressId',
},
},
},
Address: {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: 'addressId', value: 'p.text().notNull()' },
{ key: 'chainId', value: 'p.text().notNull()' },
{ key: 'type', value: 'p.text().notNull()' },
{ key: 'searchable', value: 'p.text()' },
{ key: 'timestamp', value: 'p.bigint().notNull()' },
],
relations: {
address: {
type: 'one',
name: 'address',
table: 'globalAddress',
fields: ['addressId'],
references: ['id'],
},
chain: {
type: 'one',
name: 'chain',
table: 'chain',
fields: ['chainId'],
references: ['id'],
},
txsFrom: {
type: 'many',
name: 'txsFrom',
table: 'tx',
relationName: 'fromId',
},
txsTo: {
type: 'many',
name: 'txsTo',
table: 'tx',
relationName: 'toId',
},
},
},
Scope: {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: 'name', value: 'p.text().notNull()' },
{ key: 'addressId', value: 'p.text().notNull()' },
{ key: 'txId', value: 'p.text().notNull()' },
{ key: 'chainId', value: 'p.text().notNull()' },
{ key: 'timestamp', value: 'p.bigint().notNull()' },
],
relations: {
address: {
type: 'one',
name: 'address',
table: 'address',
fields: ['addressId'],
references: ['id'],
},
tx: {
type: 'one',
name: 'tx',
table: 'tx',
fields: ['txId'],
references: ['id'],
},
chain: {
type: 'one',
name: 'chain',
table: 'chain',
fields: ['chainId'],
references: ['id'],
},
},
},
Contract: {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: 'name', value: 'p.text().notNull()' },
{ key: 'symbol', value: 'p.text().notNull()' },
{ key: 'chainId', value: 'p.text().notNull()' },
{ key: 'address', value: 'p.hex().notNull()' },
{ key: 'baseURI', value: 'p.text().notNull()' },
{ key: 'schemaURI', value: 'p.text().notNull()' },
{ key: 'imageURI', value: 'p.text().notNull()' },
{ key: 'timestamp', value: 'p.bigint().notNull()' },
],
relations: {
chain: {
type: 'one',
name: 'chain',
table: 'chain',
fields: ['chainId'],
references: ['id'],
},
},
},
};
return tables;
}
function getUserContractTableStructure(projectConfig) {
const fragmentRelationships = (0, config_1.getFragmentRelationships)(projectConfig);
const tables = {};
Object.entries(projectConfig.contracts).forEach(([contractName, contractConfig]) => {
if (typeof contractConfig === 'string')
return;
const table = {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: 'owner', value: 'p.hex().notNull()' },
{ key: 'tokenId', value: 'p.bigint().notNull()' },
{ key: 'mintTxId', value: 'p.text().notNull()' },
{ key: 'burnTxId', value: 'p.text()' },
{ key: 'contractId', value: 'p.text().notNull()' },
],
relations: {
mintTx: {
type: 'one',
name: 'mintTx',
table: 'tx',
fields: ['mintTxId'],
references: ['id'],
},
burnTx: {
type: 'one',
name: 'burnTx',
table: 'tx',
fields: ['burnTxId'],
references: ['id'],
},
contract: {
type: 'one',
name: 'contract',
table: 'contract',
fields: ['contractId'],
references: ['id'],
},
},
};
contractConfig.fields.forEach((field) => {
if (field.type === 'literef' || field.arrayLength) {
// Create a separate table for literef or array fields
const refTableName = `${contractName}${_.camelCase(field.key)}`;
const refTable = {
fields: [
{ key: 'id', value: 'p.text().primaryKey()' },
{ key: `${_.camelCase(contractName)}Id`, value: `p.text().notNull()` },
{ key: 'value', value: `${getFieldType(field.type)}.notNull()` },
{ key: 'timestamp', value: 'p.bigint().notNull()' },
],
relations: {},
};
refTable.relations[_.camelCase(contractName)] = {
type: 'one',
name: 'contract',
table: _.camelCase(contractName),
fields: [`${_.camelCase(contractName)}Id`],
references: ['id'],
};
table.relations[field.key] = {
type: 'many',
name: field.key,
table: _.camelCase(refTableName),
relationName: `${_.camelCase(contractName)}`,
};
tables[refTableName] = refTable;
}
else {
table.fields.push({
key: field.key,
value: `${getFieldType(field.type)}`,
});
}
});
if (fragmentRelationships[contractName]) {
fragmentRelationships[contractName].forEach((relation) => {
table.fields.push({
key: _.camelCase(`${relation}Id`),
value: `p.text()`,
});
table.relations[_.camelCase(relation)] = {
type: 'one',
name: _.camelCase(relation),
table: _.camelCase(relation),
fields: [`${_.camelCase(relation)}Id`],
references: ['id'],
};
});
}
contractConfig.fragments?.forEach((fragment) => {
table.relations[_.camelCase(fragment)] = {
type: 'many',
name: _.camelCase(fragment),
table: _.camelCase(fragment),
relationName: `${_.camelCase(contractName)}Id`,
};
});
table.fields.push({ key: 'timestamp', value: 'p.bigint()' });
tables[contractName] = table;
});
return tables;
}
function getFieldType(type) {
switch (type) {
case 'boolean':
return 'p.boolean()';
case 'int8':
case 'int16':
case 'int32':
case 'uint8':
case 'uint16':
case 'uint32':
return 'p.integer()';
case 'int64':
case 'int128':
case 'int256':
case 'uint64':
case 'uint128':
case 'uint256':
return 'p.bigint()';
case 'address':
return 'p.hex()';
case 'char8':
case 'char16':
case 'char32':
case 'char64':
case 'string':
return 'p.text()';
default:
return 'p.text()';
}
}
function renderSchemaFile(enums, tables) {
const output = [];
output.push(`import { index, onchainTable, relations } from "@ponder/core";`);
Object.entries(tables).forEach(([tableName, table]) => {
output.push(`export const ${_.camelCase(tableName)} = onchainTable('${_.snakeCase(tableName)}', (p) => ({
${table.fields.map((field) => `${field.key}: ${field.value}`).join(',\n')}
}));\n`);
const includes = new Set();
for (const [relationName, relation] of Object.entries(table.relations)) {
includes.add(relation.type);
}
const include = includes.size > 0 ? `${[...includes].join(',')}` : '';
if (Object.keys(table.relations).length > 0) {
output.push(`export const ${_.camelCase(tableName)}Relations = relations(${_.camelCase(tableName)}, ({${include}}) => ({
${Object.entries(table.relations).map(([relationName, relation]) => {
if (relation.type === 'one') {
return `${relation.name}: ${relation.type}(${relation.table},{
fields:[${relation.fields.map((field) => `${_.camelCase(tableName)}.${field}`).join(',')}],
references:[${relation.references.map((field) => `${_.camelCase(relation.table)}.${field}`).join(',')}]
})
`;
}
else {
return `${relation.name}: ${relation.type}(${relation.table},{
relationName:'${relation.name}',
})
`;
}
})}
}));\n`);
}
});
return output.join('\n');
}