UNPKG

@patchworkdev/pdk

Version:

Patchwork Development Kit

431 lines (429 loc) 16.1 kB
"use strict"; 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'); }