diff --git a/.changeset/tangy-pants-buy.md b/.changeset/tangy-pants-buy.md new file mode 100644 index 000000000..f8af21c02 --- /dev/null +++ b/.changeset/tangy-pants-buy.md @@ -0,0 +1,5 @@ +--- +'@graphprotocol/graph-cli': minor +--- + +require immutable flag on entities diff --git a/examples/arweave-blocks-transactions/schema.graphql b/examples/arweave-blocks-transactions/schema.graphql index 3c8843df1..85342ac54 100644 --- a/examples/arweave-blocks-transactions/schema.graphql +++ b/examples/arweave-blocks-transactions/schema.graphql @@ -1,4 +1,4 @@ -type Block @entity { +type Block @entity(immutable: true) { id: ID! timestamp: BigInt! @@ -22,7 +22,7 @@ type Block @entity { poa: Poa } -type Transaction @entity { +type Transaction @entity(immutable: true) { id: ID! block: Block! @@ -39,7 +39,7 @@ type Transaction @entity { reward: Bytes! } -type Poa @entity { +type Poa @entity(immutable: true) { id: ID! option: String! @@ -48,7 +48,7 @@ type Poa @entity { chunk: Bytes! } -type Tag @entity { +type Tag @entity(immutable: true) { id: ID! name: Bytes! diff --git a/examples/cosmos-block-filtering/schema.graphql b/examples/cosmos-block-filtering/schema.graphql index 803f5c7e6..c52d5b4f8 100644 --- a/examples/cosmos-block-filtering/schema.graphql +++ b/examples/cosmos-block-filtering/schema.graphql @@ -1,4 +1,4 @@ -type Block @entity { +type Block @entity(immutable: true) { id: ID! number: BigInt timestamp: BigInt diff --git a/examples/cosmos-osmosis-token-swaps/schema.graphql b/examples/cosmos-osmosis-token-swaps/schema.graphql index baffd4b0f..c6f24ecda 100644 --- a/examples/cosmos-osmosis-token-swaps/schema.graphql +++ b/examples/cosmos-osmosis-token-swaps/schema.graphql @@ -1,10 +1,10 @@ -type Token @entity { +type Token @entity(immutable: true) { id: ID! amount: String denom: String } -type TokenSwap @entity { +type TokenSwap @entity(immutable: true) { id: ID! sender: String poolId: String diff --git a/examples/cosmos-validator-delegations/schema.graphql b/examples/cosmos-validator-delegations/schema.graphql index 11b1433eb..a717049ea 100644 --- a/examples/cosmos-validator-delegations/schema.graphql +++ b/examples/cosmos-validator-delegations/schema.graphql @@ -1,11 +1,11 @@ -type Delegation @entity { +type Delegation @entity(immutable: true) { id: ID! delegatorAddress: String validatorAddress: String amount: Coin } -type Coin @entity { +type Coin @entity(immutable: true) { id: ID! denom: String amount: String diff --git a/examples/cosmos-validator-rewards/schema.graphql b/examples/cosmos-validator-rewards/schema.graphql index c6863ca43..6bd20b143 100644 --- a/examples/cosmos-validator-rewards/schema.graphql +++ b/examples/cosmos-validator-rewards/schema.graphql @@ -1,4 +1,4 @@ -type Reward @entity { +type Reward @entity(immutable: true) { id: ID! amount: String validator: String diff --git a/examples/ethereum-basic-event-handlers/schema.graphql b/examples/ethereum-basic-event-handlers/schema.graphql index cf8774f1b..928e5b915 100644 --- a/examples/ethereum-basic-event-handlers/schema.graphql +++ b/examples/ethereum-basic-event-handlers/schema.graphql @@ -1,11 +1,11 @@ -type NewGravatar @entity { +type NewGravatar @entity(immutable: false) { id: ID! owner: Bytes! displayName: String! imageUrl: String! } -type UpdatedGravatar @entity { +type UpdatedGravatar @entity(immutable: false) { id: ID! owner: Bytes! displayName: String! diff --git a/examples/ethereum-gravatar/schema.graphql b/examples/ethereum-gravatar/schema.graphql index f45302439..e16b211a6 100644 --- a/examples/ethereum-gravatar/schema.graphql +++ b/examples/ethereum-gravatar/schema.graphql @@ -1,4 +1,4 @@ -type Gravatar @entity { +type Gravatar @entity(immutable: false) { id: ID! owner: Bytes! displayName: String! diff --git a/examples/example-subgraph/schema.graphql b/examples/example-subgraph/schema.graphql index f72b1bcf3..ac473835c 100644 --- a/examples/example-subgraph/schema.graphql +++ b/examples/example-subgraph/schema.graphql @@ -1,4 +1,4 @@ -type ExampleEntity @entity { +type ExampleEntity @entity(immutable: false) { id: ID! optionalBoolean: Boolean @@ -32,6 +32,6 @@ type ExampleEntity @entity { requiredReferenceList: [OtherEntity!]! } -type OtherEntity @entity { +type OtherEntity @entity(immutable: true) { id: ID! } diff --git a/examples/near-blocks/schema.graphql b/examples/near-blocks/schema.graphql index e72cca3ef..acd43629d 100644 --- a/examples/near-blocks/schema.graphql +++ b/examples/near-blocks/schema.graphql @@ -1,4 +1,4 @@ -type BlockEvent @entity { +type BlockEvent @entity(immutable: true) { id: ID! number: BigInt hash: Bytes diff --git a/examples/near-receipts/schema.graphql b/examples/near-receipts/schema.graphql index b6347b282..c81680fef 100644 --- a/examples/near-receipts/schema.graphql +++ b/examples/near-receipts/schema.graphql @@ -1,10 +1,10 @@ -type Greeter @entity { +type Greeter @entity(immutable: true) { id: ID! name: String! greetings: [Greeting!] @derivedFrom(field: "greeter") } -type Greeting @entity { +type Greeting @entity(immutable: true) { id: ID! greeter: Greeter! timestamp: BigInt! diff --git a/examples/substreams-powered-subgraph/schema.graphql b/examples/substreams-powered-subgraph/schema.graphql index 7b1c7d114..7f2b80082 100644 --- a/examples/substreams-powered-subgraph/schema.graphql +++ b/examples/substreams-powered-subgraph/schema.graphql @@ -1,4 +1,4 @@ -type Contract @entity { +type Contract @entity(immutable: true) { id: ID! "The timestamp when the contract was deployed" diff --git a/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap index ae7426d0a..ad641383f 100644 --- a/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap +++ b/packages/cli/src/scaffold/__snapshots__/cosmos.test.ts.snap @@ -60,7 +60,7 @@ export function handleBlock(block: cosmos.Block): void { `; exports[`Cosmos subgraph scaffolding > Schema (default) 1`] = ` -"type ExampleEntity @entity { +"type ExampleEntity @entity(immutable: true) { id: ID! block: Bytes! count: BigInt! diff --git a/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap index bad4cbb02..32e19c553 100644 --- a/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap +++ b/packages/cli/src/scaffold/__snapshots__/ethereum.test.ts.snap @@ -227,7 +227,7 @@ export function handleTupleArrayEvent(event: TupleArrayEvent): void {} `; exports[`Ethereum subgraph scaffolding > Schema (default) 1`] = ` -"type ExampleEntity @entity { +"type ExampleEntity @entity(immutable: true) { id: Bytes! count: BigInt! a: BigInt! # uint256 diff --git a/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap b/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap index ff2ef9326..b4aec1b2f 100644 --- a/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap +++ b/packages/cli/src/scaffold/__snapshots__/near.test.ts.snap @@ -62,7 +62,7 @@ export function handleReceipt( `; exports[`NEAR subgraph scaffolding > Schema (default) 1`] = ` -"type ExampleEntity @entity { +"type ExampleEntity @entity(immutable: true) { id: ID! block: Bytes! count: BigInt! diff --git a/packages/cli/src/scaffold/schema.ts b/packages/cli/src/scaffold/schema.ts index 9f66b5063..ce6d82187 100644 --- a/packages/cli/src/scaffold/schema.ts +++ b/packages/cli/src/scaffold/schema.ts @@ -85,7 +85,7 @@ export const generateEventType = ( export const generateExampleEntityType = (protocol: Protocol, events: any[]) => { if (protocol.hasABIs() && events.length > 0) { - return `type ExampleEntity @entity { + return `type ExampleEntity @entity(immutable: true) { id: Bytes! count: BigInt! ${events[0].inputs @@ -97,7 +97,7 @@ export const generateExampleEntityType = (protocol: Protocol, events: any[]) => .join('\n')} }`; } - return `type ExampleEntity @entity { + return `type ExampleEntity @entity(immutable: true) { id: ID! block: Bytes! count: BigInt! diff --git a/packages/cli/src/schema.ts b/packages/cli/src/schema.ts index 25e93a5a3..9f935fe05 100644 --- a/packages/cli/src/schema.ts +++ b/packages/cli/src/schema.ts @@ -42,4 +42,31 @@ export default class Schema { ) .map(entity => (entity as graphql.ObjectTypeDefinitionNode).name.value); } + + immutableEntitiesCount(): number { + const isImmutable = (entity: graphql.ConstDirectiveNode) => { + return ( + entity.arguments?.find(arg => { + return ( + (arg.name.value === 'immutable' || arg.name.value === 'timeseries') && + arg.value.kind === 'BooleanValue' && + arg.value.value + ); + }) !== undefined + ); + }; + + return this.ast.definitions.filter(def => { + if (def.kind !== 'ObjectTypeDefinition') { + return false; + } + + const entity = def.directives?.find(directive => directive.name.value === 'entity'); + if (entity === undefined) { + return false; + } + + return isImmutable(entity); + }).length; + } } diff --git a/packages/cli/src/type-generator.ts b/packages/cli/src/type-generator.ts index ece607624..b38d5c35b 100644 --- a/packages/cli/src/type-generator.ts +++ b/packages/cli/src/type-generator.ts @@ -102,6 +102,14 @@ export default class TypeGenerator { typeGenDebug.extend('generateTypes')('Generating types for schema'); await this.generateTypesForSchema({ schema }); + if (schema.immutableEntitiesCount() === 0) { + toolbox.print.warning( + '\nThe GraphQL schema does not take advantage of using immutable entities. ' + + 'Immutable entities can significantly improve subgraph performance.\n' + + 'Learn more about using immutable entities: https://thegraph.com/docs/en/subgraphs/best-practices/immutable-entities-bytes-as-ids/#immutable-entities', + ); + } + if (this.options.subgraphSources.length > 0) { const ipfsClient = createIpfsClient({ url: appendApiVersionForGraph(this.options.ipfsUrl.toString()), diff --git a/packages/cli/src/validation/schema.ts b/packages/cli/src/validation/schema.ts index b62cf0bd6..7cfcd1af5 100644 --- a/packages/cli/src/validation/schema.ts +++ b/packages/cli/src/validation/schema.ts @@ -1,4 +1,5 @@ import fs from 'node:fs'; +import { print } from 'gluegun'; import * as graphql from 'graphql/language/index.js'; import immutable from 'immutable'; import debugFactory from '../debug.js'; @@ -99,6 +100,36 @@ const validateEntityDirective = (def: any) => { ]); }; +const validateEntityDirectiveImmutableArgument = (def: graphql.ObjectTypeDefinitionNode) => { + validateDebugger('Validating immutable argument on entity directive for %s', def?.name?.value); + + const entity = def.directives?.find(directive => directive.name.value === 'entity'); + if (entity === undefined) { + return List(); + } + + const hasImmutableArg = + entity.arguments?.find(arg => arg.name.value === 'immutable') !== undefined; + const hasTimeseriesArg = + entity.arguments?.find(arg => arg.name.value === 'timeseries') !== undefined; + + if (hasImmutableArg || hasTimeseriesArg) { + return List(); + } + + return immutable.fromJS([ + { + loc: def.loc, + entity: def.name?.value, + message: + `@entity directive requires \`immutable\` argument\n ` + + print.colors.yellow( + `Hint: Try updating the entity definition with: @entity(immutable: true)`, + ), + }, + ]); +}; + const validateEntityID = (def: any) => { validateDebugger('Validating entity ID for %s', def?.name?.value); const idField = def.fields.find((field: any) => field.name.value === 'id'); @@ -986,6 +1017,7 @@ const typeDefinitionValidators = { ? List.of(...validateSubgraphSchemaDirectives(def), ...validateTypeHasNoFields(def)) : List.of( ...validateEntityDirective(def), + ...validateEntityDirectiveImmutableArgument(def), ...validateEntityID(def), ...validateEntityFields(defs, def), ...validateNoImportDirective(def), diff --git a/packages/cli/tests/cli/__snapshots__/validation.test.ts.snap b/packages/cli/tests/cli/__snapshots__/validation.test.ts.snap index 2fbee61b8..ea81066dc 100644 --- a/packages/cli/tests/cli/__snapshots__/validation.test.ts.snap +++ b/packages/cli/tests/cli/__snapshots__/validation.test.ts.snap @@ -932,6 +932,20 @@ Types generated successfully " `; +exports[`Validation > Should require immutable argument on entity directive 1`] = ` +"- Load subgraph from subgraph.yaml +✖ Failed to load subgraph from subgraph.yaml: Error in schema.graphql: + + EntityA: + - @entity directive requires \`immutable\` argument + Hint: Try updating the entity definition with: @entity(immutable: true) +" +`; + +exports[`Validation > Should require immutable argument on entity directive 2`] = `1`; + +exports[`Validation > Should require immutable argument on entity directive 3`] = `""`; + exports[`Validation > Source without address is valid 1`] = ` "- Load subgraph from subgraph.yaml ✔ Load subgraph from subgraph.yaml diff --git a/packages/cli/tests/cli/add/subgraph/schema.graphql b/packages/cli/tests/cli/add/subgraph/schema.graphql index cf8774f1b..b8fe962e4 100644 --- a/packages/cli/tests/cli/add/subgraph/schema.graphql +++ b/packages/cli/tests/cli/add/subgraph/schema.graphql @@ -1,11 +1,11 @@ -type NewGravatar @entity { +type NewGravatar @entity(immutable: true) { id: ID! owner: Bytes! displayName: String! imageUrl: String! } -type UpdatedGravatar @entity { +type UpdatedGravatar @entity(immutable: true) { id: ID! owner: Bytes! displayName: String! diff --git a/packages/cli/tests/cli/validation.test.ts b/packages/cli/tests/cli/validation.test.ts index 81a7838f4..aeb90211a 100644 --- a/packages/cli/tests/cli/validation.test.ts +++ b/packages/cli/tests/cli/validation.test.ts @@ -247,4 +247,13 @@ describe('Validation', { concurrent: true, timeout: 60_000 }, () => { exitCode: 0, }, ); + + cliTest( + 'Should require immutable argument on entity directive', + ['codegen', '--skip-migrations'], + 'validation/require-immutable-argument', + { + exitCode: 1, + }, + ); }); diff --git a/packages/cli/tests/cli/validation/2d-array-is-valid/schema.graphql b/packages/cli/tests/cli/validation/2d-array-is-valid/schema.graphql index 37e62eb4c..91dad2a14 100644 --- a/packages/cli/tests/cli/validation/2d-array-is-valid/schema.graphql +++ b/packages/cli/tests/cli/validation/2d-array-is-valid/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! childTokenURIs: [[String!]!]! # string[][] } diff --git a/packages/cli/tests/cli/validation/3d-array-is-valid/schema.graphql b/packages/cli/tests/cli/validation/3d-array-is-valid/schema.graphql index bd0b76088..6b4e87196 100644 --- a/packages/cli/tests/cli/validation/3d-array-is-valid/schema.graphql +++ b/packages/cli/tests/cli/validation/3d-array-is-valid/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! childTokenURIs: [[[String!]!]!]! # string[][][] } diff --git a/packages/cli/tests/cli/validation/abi-not-found/schema.graphql b/packages/cli/tests/cli/validation/abi-not-found/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/abi-not-found/schema.graphql +++ b/packages/cli/tests/cli/validation/abi-not-found/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/big-decimal-is-valid/schema.graphql b/packages/cli/tests/cli/validation/big-decimal-is-valid/schema.graphql index 218c5b9c2..1edfc3c6c 100644 --- a/packages/cli/tests/cli/validation/big-decimal-is-valid/schema.graphql +++ b/packages/cli/tests/cli/validation/big-decimal-is-valid/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! x: BigDecimal! } diff --git a/packages/cli/tests/cli/validation/block-handler-filters/schema.graphql b/packages/cli/tests/cli/validation/block-handler-filters/schema.graphql index 79d10a400..98b9b177a 100644 --- a/packages/cli/tests/cli/validation/block-handler-filters/schema.graphql +++ b/packages/cli/tests/cli/validation/block-handler-filters/schema.graphql @@ -1,3 +1,3 @@ -type A @entity { +type A @entity(immutable: true) { id: ID! -} \ No newline at end of file +} diff --git a/packages/cli/tests/cli/validation/call-function-not-found/schema.graphql b/packages/cli/tests/cli/validation/call-function-not-found/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/call-function-not-found/schema.graphql +++ b/packages/cli/tests/cli/validation/call-function-not-found/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/call-handler-with-tuple/schema.graphql b/packages/cli/tests/cli/validation/call-handler-with-tuple/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/call-handler-with-tuple/schema.graphql +++ b/packages/cli/tests/cli/validation/call-handler-with-tuple/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/conflicting-network-names/schema.graphql b/packages/cli/tests/cli/validation/conflicting-network-names/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/conflicting-network-names/schema.graphql +++ b/packages/cli/tests/cli/validation/conflicting-network-names/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/conflicting-protocol-names/schema.graphql b/packages/cli/tests/cli/validation/conflicting-protocol-names/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/conflicting-protocol-names/schema.graphql +++ b/packages/cli/tests/cli/validation/conflicting-protocol-names/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/derived-from-target-type-missing/schema.graphql b/packages/cli/tests/cli/validation/derived-from-target-type-missing/schema.graphql index c3cc44b10..d43afb1e7 100644 --- a/packages/cli/tests/cli/validation/derived-from-target-type-missing/schema.graphql +++ b/packages/cli/tests/cli/validation/derived-from-target-type-missing/schema.graphql @@ -1,4 +1,4 @@ -type Foo @entity { +type Foo @entity(immutable: true) { id: ID! bars: [Bars!]! @derivedFrom(field: "foo") } diff --git a/packages/cli/tests/cli/validation/derived-from-with-interface/schema.graphql b/packages/cli/tests/cli/validation/derived-from-with-interface/schema.graphql index 422682703..cfe420f39 100644 --- a/packages/cli/tests/cli/validation/derived-from-with-interface/schema.graphql +++ b/packages/cli/tests/cli/validation/derived-from-with-interface/schema.graphql @@ -1,4 +1,4 @@ -type Gravatar @entity { +type Gravatar @entity(immutable: false) { id: ID! # This field points at an interface; we allow that a derived field # in a type that implements the interface derives from this field @@ -12,7 +12,7 @@ interface Account { gravatars: [Gravatar!]! @derivedFrom(field: "owner") } -type UserAccount implements Account @entity { +type UserAccount implements Account @entity(immutable: true) { id: ID! name: String! gravatars: [Gravatar!]! @derivedFrom(field: "owner") diff --git a/packages/cli/tests/cli/validation/duplicate-data-source-name/schema.graphql b/packages/cli/tests/cli/validation/duplicate-data-source-name/schema.graphql index 218c5b9c2..1edfc3c6c 100644 --- a/packages/cli/tests/cli/validation/duplicate-data-source-name/schema.graphql +++ b/packages/cli/tests/cli/validation/duplicate-data-source-name/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! x: BigDecimal! } diff --git a/packages/cli/tests/cli/validation/duplicate-template-name/schema.graphql b/packages/cli/tests/cli/validation/duplicate-template-name/schema.graphql index 218c5b9c2..1edfc3c6c 100644 --- a/packages/cli/tests/cli/validation/duplicate-template-name/schema.graphql +++ b/packages/cli/tests/cli/validation/duplicate-template-name/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! x: BigDecimal! } diff --git a/packages/cli/tests/cli/validation/entity-field-args/schema.graphql b/packages/cli/tests/cli/validation/entity-field-args/schema.graphql index 31a2be445..7fc28009e 100644 --- a/packages/cli/tests/cli/validation/entity-field-args/schema.graphql +++ b/packages/cli/tests/cli/validation/entity-field-args/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! foo(bar: Int!): Int! } diff --git a/packages/cli/tests/cli/validation/ethereum-contract-without-handlers/schema.graphql b/packages/cli/tests/cli/validation/ethereum-contract-without-handlers/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/ethereum-contract-without-handlers/schema.graphql +++ b/packages/cli/tests/cli/validation/ethereum-contract-without-handlers/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/event-not-found/schema.graphql b/packages/cli/tests/cli/validation/event-not-found/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/event-not-found/schema.graphql +++ b/packages/cli/tests/cli/validation/event-not-found/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/example-values-found/schema.graphql b/packages/cli/tests/cli/validation/example-values-found/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/example-values-found/schema.graphql +++ b/packages/cli/tests/cli/validation/example-values-found/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/indexer-hints/schema.graphql b/packages/cli/tests/cli/validation/indexer-hints/schema.graphql index 218c5b9c2..1edfc3c6c 100644 --- a/packages/cli/tests/cli/validation/indexer-hints/schema.graphql +++ b/packages/cli/tests/cli/validation/indexer-hints/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! x: BigDecimal! } diff --git a/packages/cli/tests/cli/validation/invalid-abis/schema.graphql b/packages/cli/tests/cli/validation/invalid-abis/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/invalid-abis/schema.graphql +++ b/packages/cli/tests/cli/validation/invalid-abis/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/invalid-contract-addresses/schema.graphql b/packages/cli/tests/cli/validation/invalid-contract-addresses/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/invalid-contract-addresses/schema.graphql +++ b/packages/cli/tests/cli/validation/invalid-contract-addresses/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/invalid-data-source-template/schema.graphql b/packages/cli/tests/cli/validation/invalid-data-source-template/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/invalid-data-source-template/schema.graphql +++ b/packages/cli/tests/cli/validation/invalid-data-source-template/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/invalid-entity-field-types/schema.graphql b/packages/cli/tests/cli/validation/invalid-entity-field-types/schema.graphql index 7bd510a07..e09396486 100644 --- a/packages/cli/tests/cli/validation/invalid-entity-field-types/schema.graphql +++ b/packages/cli/tests/cli/validation/invalid-entity-field-types/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! isSet1: bool diff --git a/packages/cli/tests/cli/validation/invalid-fulltext-directive/schema.graphql b/packages/cli/tests/cli/validation/invalid-fulltext-directive/schema.graphql index e9f26c94b..96b6b613e 100644 --- a/packages/cli/tests/cli/validation/invalid-fulltext-directive/schema.graphql +++ b/packages/cli/tests/cli/validation/invalid-fulltext-directive/schema.graphql @@ -117,7 +117,7 @@ type _Schema_ } ] ) -type A @entity @fulltext( +type A @entity(immutable: true) @fulltext( name: "FulltextOnWrongType" language: en algorithm: rank @@ -134,7 +134,7 @@ type A @entity @fulltext( id: ID! } -type B @entity { +type B @entity(immutable: true) { id: ID! foo: String! } diff --git a/packages/cli/tests/cli/validation/invalid-graphql-schema/schema.graphql b/packages/cli/tests/cli/validation/invalid-graphql-schema/schema.graphql index 33ef8f4be..350d9b093 100644 --- a/packages/cli/tests/cli/validation/invalid-graphql-schema/schema.graphql +++ b/packages/cli/tests/cli/validation/invalid-graphql-schema/schema.graphql @@ -1,8 +1,8 @@ -type Something @entity { +type Something @entity(immutable: true) { id: ID! } -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! invalidField: [Something]! } diff --git a/packages/cli/tests/cli/validation/missing-entity-id/schema.graphql b/packages/cli/tests/cli/validation/missing-entity-id/schema.graphql index ed0670aa7..bba9058a4 100644 --- a/packages/cli/tests/cli/validation/missing-entity-id/schema.graphql +++ b/packages/cli/tests/cli/validation/missing-entity-id/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { name: String! } diff --git a/packages/cli/tests/cli/validation/missing-or-invalid-derived-from-fields/schema.graphql b/packages/cli/tests/cli/validation/missing-or-invalid-derived-from-fields/schema.graphql index 1894f34e1..5e182fb18 100644 --- a/packages/cli/tests/cli/validation/missing-or-invalid-derived-from-fields/schema.graphql +++ b/packages/cli/tests/cli/validation/missing-or-invalid-derived-from-fields/schema.graphql @@ -1,4 +1,4 @@ -type A @entity { +type A @entity(immutable: true) { id: ID! b: B @derivedFrom(field: "a") c: [C!]! @derivedFrom(field: "a") @@ -9,32 +9,32 @@ type A @entity { h: H @derivedFrom(field: "a") } -type B @entity { +type B @entity(immutable: true) { id: ID! } -type C @entity { +type C @entity(immutable: true) { id: ID! } -type D @entity { +type D @entity(immutable: true) { id: ID! } -type E @entity { +type E @entity(immutable: true) { id: ID! } -type F @entity { +type F @entity(immutable: true) { id: ID! } -type G @entity { +type G @entity(immutable: true) { id: ID! a: BigInt } -type H @entity { +type H @entity(immutable: true) { id: ID! a: A! } diff --git a/packages/cli/tests/cli/validation/near-is-valid/schema.graphql b/packages/cli/tests/cli/validation/near-is-valid/schema.graphql index ddf2095ee..c15de8351 100644 --- a/packages/cli/tests/cli/validation/near-is-valid/schema.graphql +++ b/packages/cli/tests/cli/validation/near-is-valid/schema.graphql @@ -1,8 +1,8 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! x: Account! } -type Account @entity { +type Account @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/nested-template-nice-error/schema.graphql b/packages/cli/tests/cli/validation/nested-template-nice-error/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/nested-template-nice-error/schema.graphql +++ b/packages/cli/tests/cli/validation/nested-template-nice-error/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/no-network-names/schema.graphql b/packages/cli/tests/cli/validation/no-network-names/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/no-network-names/schema.graphql +++ b/packages/cli/tests/cli/validation/no-network-names/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/require-immutable-argument.stderr b/packages/cli/tests/cli/validation/require-immutable-argument.stderr new file mode 100644 index 000000000..a0896befc --- /dev/null +++ b/packages/cli/tests/cli/validation/require-immutable-argument.stderr @@ -0,0 +1,6 @@ +- Load subgraph from subgraph.yaml +✖ Failed to load subgraph from subgraph.yaml: Error in schema.graphql: + + EntityA: + - @entity directive requires `immutable` argument + Hint: Try updating the entity definition with: @entity(immutable: true) diff --git a/packages/cli/tests/cli/validation/require-immutable-argument/Abi.json b/packages/cli/tests/cli/validation/require-immutable-argument/Abi.json new file mode 100644 index 000000000..4d05f5839 --- /dev/null +++ b/packages/cli/tests/cli/validation/require-immutable-argument/Abi.json @@ -0,0 +1,7 @@ +[ + { + "type": "event", + "name": "ExampleEvent", + "inputs": [{ "type": "string" }] + } +] diff --git a/packages/cli/tests/cli/validation/require-immutable-argument/mapping.ts b/packages/cli/tests/cli/validation/require-immutable-argument/mapping.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/cli/tests/cli/validation/require-immutable-argument/schema.graphql b/packages/cli/tests/cli/validation/require-immutable-argument/schema.graphql new file mode 100644 index 000000000..6934ebc29 --- /dev/null +++ b/packages/cli/tests/cli/validation/require-immutable-argument/schema.graphql @@ -0,0 +1,19 @@ +# Entity is not valid because it is missing the immutable argument; +type EntityA @entity { + id: ID! +} + +# Entity is valid because it has the immutable argument; +type EntityB @entity(immutable: true) { + id: ID! +} + +# Entity is valid because it has the immutable argument; +type EntityC @entity(immutable: false) { + id: ID! +} + +# Entity is valid because the timeseries argument ensures immutability; +type EntityD @entity(timeseries: true) { + id: ID! +} diff --git a/packages/cli/tests/cli/validation/require-immutable-argument/subgraph.yaml b/packages/cli/tests/cli/validation/require-immutable-argument/subgraph.yaml new file mode 100644 index 000000000..901269f2c --- /dev/null +++ b/packages/cli/tests/cli/validation/require-immutable-argument/subgraph.yaml @@ -0,0 +1,25 @@ +specVersion: 0.0.1 +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum/contract + name: ExampleContract + source: + address: '22843e74c59580b3eaf6c233fa67d8b7c561a835' + abi: ExampleEvent + mapping: + kind: ethereum/events + apiVersion: 0.0.5 + language: wasm/assemblyscript + file: ./mapping.ts + entities: + - EntityA + - EntityB + - EntityC + - EntityD + abis: + - name: ExampleEvent + file: ./Abi.json + eventHandlers: + - event: ExampleEvent(string) + handler: handleExampleEvent diff --git a/packages/cli/tests/cli/validation/source-without-address-is-valid/schema.graphql b/packages/cli/tests/cli/validation/source-without-address-is-valid/schema.graphql index 2fa61d542..d5a41952b 100644 --- a/packages/cli/tests/cli/validation/source-without-address-is-valid/schema.graphql +++ b/packages/cli/tests/cli/validation/source-without-address-is-valid/schema.graphql @@ -1,3 +1,3 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! } diff --git a/packages/cli/tests/cli/validation/topic0-is-valid/schema.graphql b/packages/cli/tests/cli/validation/topic0-is-valid/schema.graphql index 218c5b9c2..1edfc3c6c 100644 --- a/packages/cli/tests/cli/validation/topic0-is-valid/schema.graphql +++ b/packages/cli/tests/cli/validation/topic0-is-valid/schema.graphql @@ -1,4 +1,4 @@ -type MyEntity @entity { +type MyEntity @entity(immutable: true) { id: ID! x: BigDecimal! }