ソースを参照

remove hydra related code

metmirr 4 年 前
コミット
835b9dc8fd
100 ファイル変更0 行追加5190 行削除
  1. 0 0
      query-node/bootstrap/index.ts
  2. 0 0
      query-node/bootstrap/members.ts
  3. 0 0
      query-node/bootstrap/package-lock.json
  4. 0 0
      query-node/bootstrap/package.json
  5. 0 0
      query-node/bootstrap/tsconfig.json
  6. 0 20
      query-node/docs/README.md
  7. 0 19
      query-node/docs/architecture.md
  8. 0 140
      query-node/docs/entity-relationship.md
  9. 0 0
      query-node/docs/indexer.md
  10. 0 53
      query-node/docs/install-hydra.md
  11. 0 73
      query-node/docs/manifest-spec.md
  12. 0 51
      query-node/docs/mappings/README.md
  13. 0 41
      query-node/docs/mappings/databasemanager.md
  14. 0 31
      query-node/docs/mappings/substrateevent.md
  15. 0 106
      query-node/docs/quick-start.md
  16. 0 15
      query-node/docs/schema-spec.md
  17. 0 16
      query-node/docs/schema-spec/README.md
  18. 0 51
      query-node/docs/schema-spec/entities.md
  19. 0 144
      query-node/docs/schema-spec/entity-relationship.md
  20. 0 17
      query-node/docs/schema-spec/enums.md
  21. 0 55
      query-node/docs/schema-spec/full-text-queries.md
  22. 0 43
      query-node/docs/schema-spec/interfaces.md
  23. 0 57
      query-node/docs/schema-spec/the-query-goodies.md
  24. 0 54
      query-node/docs/schema-spec/variant-types.md
  25. 0 2
      query-node/examples/README.md
  26. 0 2
      query-node/examples/kusama-query-node.md
  27. 0 11
      query-node/examples/kusama-query-node/.env
  28. 0 1
      query-node/examples/kusama-query-node/README.md
  29. BIN
      query-node/examples/kusama-query-node/mappings/.DS_Store
  30. 0 1
      query-node/examples/kusama-query-node/mappings/index.ts
  31. 0 2
      query-node/examples/kusama-query-node/mappings/treasury/index.ts
  32. 0 47
      query-node/examples/kusama-query-node/mappings/treasury/proposal.ts
  33. 0 77
      query-node/examples/kusama-query-node/mappings/treasury/tip.ts
  34. 0 11
      query-node/examples/kusama-query-node/package.json
  35. 0 57
      query-node/examples/kusama-query-node/schema.graphql
  36. 0 145
      query-node/joystream-query-node.md
  37. 0 12
      query-node/joystream-query-node/.env
  38. 0 145
      query-node/joystream-query-node/README.md
  39. 0 1
      query-node/joystream-query-node/mappings/index.ts
  40. 0 82
      query-node/joystream-query-node/mappings/members.ts
  41. 0 21
      query-node/joystream-query-node/schema.graphql
  42. 0 14
      query-node/joystream-query-node/scripts/reset-dev.sh
  43. 0 7
      query-node/joystream-query-node/scripts/run-dev.sh
  44. 0 16
      query-node/substrate-query-framework/README.md
  45. 0 2
      query-node/substrate-query-framework/cli/.eslintignore
  46. 0 15
      query-node/substrate-query-framework/cli/.eslintrc.js
  47. 0 9
      query-node/substrate-query-framework/cli/.gitignore
  48. 0 10
      query-node/substrate-query-framework/cli/.prettierrc.js
  49. 0 143
      query-node/substrate-query-framework/cli/README.md
  50. 0 2
      query-node/substrate-query-framework/cli/bin/README.md
  51. 0 5
      query-node/substrate-query-framework/cli/bin/run
  52. 0 3
      query-node/substrate-query-framework/cli/bin/run.cmd
  53. 0 6
      query-node/substrate-query-framework/cli/bin/run.md
  54. 0 101
      query-node/substrate-query-framework/cli/package.json
  55. 0 130
      query-node/substrate-query-framework/cli/src/commands/codegen.ts
  56. 0 21
      query-node/substrate-query-framework/cli/src/commands/db.ts
  57. 0 49
      query-node/substrate-query-framework/cli/src/commands/preview.ts
  58. 0 143
      query-node/substrate-query-framework/cli/src/commands/scaffold.ts
  59. 0 31
      query-node/substrate-query-framework/cli/src/generate/AbstractRenderer.ts
  60. 0 32
      query-node/substrate-query-framework/cli/src/generate/ConfigProvider.ts
  61. 0 44
      query-node/substrate-query-framework/cli/src/generate/EnumContextProvider.ts
  62. 0 16
      query-node/substrate-query-framework/cli/src/generate/EnumRenderer.ts
  63. 0 153
      query-node/substrate-query-framework/cli/src/generate/FTSQueryRenderer.ts
  64. 0 167
      query-node/substrate-query-framework/cli/src/generate/ModelRenderer.ts
  65. 0 157
      query-node/substrate-query-framework/cli/src/generate/RelationshipGenerator.ts
  66. 0 158
      query-node/substrate-query-framework/cli/src/generate/SourcesGenerator.ts
  67. 0 46
      query-node/substrate-query-framework/cli/src/generate/VariantsRenderer.ts
  68. 0 29
      query-node/substrate-query-framework/cli/src/generate/enum-context.ts
  69. 0 187
      query-node/substrate-query-framework/cli/src/generate/field-context.ts
  70. 0 30
      query-node/substrate-query-framework/cli/src/generate/union-context.ts
  71. 0 77
      query-node/substrate-query-framework/cli/src/generate/utils.ts
  72. 0 190
      query-node/substrate-query-framework/cli/src/helpers/WarthogWrapper.ts
  73. 0 47
      query-node/substrate-query-framework/cli/src/helpers/db.ts
  74. 0 17
      query-node/substrate-query-framework/cli/src/helpers/formatter.ts
  75. 0 17
      query-node/substrate-query-framework/cli/src/helpers/tsTypes.ts
  76. 0 10
      query-node/substrate-query-framework/cli/src/index.ts
  77. 0 21
      query-node/substrate-query-framework/cli/src/model/FTSQuery.ts
  78. 0 72
      query-node/substrate-query-framework/cli/src/model/Field.ts
  79. 0 15
      query-node/substrate-query-framework/cli/src/model/ObjectType.ts
  80. 0 39
      query-node/substrate-query-framework/cli/src/model/Relation.ts
  81. 0 16
      query-node/substrate-query-framework/cli/src/model/ScalarTypes.ts
  82. 0 249
      query-node/substrate-query-framework/cli/src/model/WarthogModel.ts
  83. 0 7
      query-node/substrate-query-framework/cli/src/model/index.ts
  84. 0 8
      query-node/substrate-query-framework/cli/src/model/validate.ts
  85. 0 36
      query-node/substrate-query-framework/cli/src/parse/DerivedFromDirective.ts
  86. 0 91
      query-node/substrate-query-framework/cli/src/parse/FTSDirective.ts
  87. 0 28
      query-node/substrate-query-framework/cli/src/parse/SchemaDirective.ts
  88. 0 174
      query-node/substrate-query-framework/cli/src/parse/SchemaParser.ts
  89. 0 242
      query-node/substrate-query-framework/cli/src/parse/WarthogModelBuilder.ts
  90. 0 22
      query-node/substrate-query-framework/cli/src/parse/constant.ts
  91. 0 14
      query-node/substrate-query-framework/cli/src/templates/db-helper.mst
  92. 0 9
      query-node/substrate-query-framework/cli/src/templates/dotenv-ormconfig.mst
  93. 0 1
      query-node/substrate-query-framework/cli/src/templates/dotenv.mst
  94. 0 7
      query-node/substrate-query-framework/cli/src/templates/entities/enums.ts.mst
  95. 0 138
      query-node/substrate-query-framework/cli/src/templates/entities/model.ts.mst
  96. 0 43
      query-node/substrate-query-framework/cli/src/templates/entities/resolver.ts.mst
  97. 0 39
      query-node/substrate-query-framework/cli/src/templates/entities/service.ts.mst
  98. 0 5
      query-node/substrate-query-framework/cli/src/templates/event-class-defination.mst
  99. 0 42
      query-node/substrate-query-framework/cli/src/templates/graphql-server.index.mst
  100. 0 185
      query-node/substrate-query-framework/cli/src/templates/index-builder-entry.mst

+ 0 - 0
query-node/joystream-query-node/bootstrap/index.ts → query-node/bootstrap/index.ts


+ 0 - 0
query-node/joystream-query-node/bootstrap/members.ts → query-node/bootstrap/members.ts


+ 0 - 0
query-node/joystream-query-node/bootstrap/package-lock.json → query-node/bootstrap/package-lock.json


+ 0 - 0
query-node/joystream-query-node/bootstrap/package.json → query-node/bootstrap/package.json


+ 0 - 0
query-node/joystream-query-node/bootstrap/tsconfig.json → query-node/bootstrap/tsconfig.json


+ 0 - 20
query-node/docs/README.md

@@ -1,20 +0,0 @@
----
-description: 'Introducing Hydra, a GraphQL query node for substrate chains'
----
-
-# Overview
-
-Hydra is inspired by [TheGraph](http://thegraph.com/) protocol but targets Substrate chains.‌
-
-Hydra is a query node for Substrate-based blockchains. A query node ingests data from a substrate chain and provides rich, domain-specific, and highly customizable access to the blockchain data, far beyond the scope of direct RPC calls. For example, expired [Kusama Treasury](https://wiki.polkadot.network/docs/en/learn-treasury) spending [proposals](https://kusama.subscan.io/event?module=Treasury&event=Proposed) are pruned from the state of the[ Kusama blockchain](https://polkascan.io/kusama), so querying, say, one-year-old proposals becomes problematic. Indeed, one has to track the evolution of the state by sequentially applying the Treasury events and extrinsics in each historical block.
-
-That's where Hydra gets you covered. Define your data model and the Hydra indexer will get it in sync with the chain. On top of that, you get a batteries-included GraphQL server with comprehensive filtering, pagination, and even full-text search capabilities. 
-
-## What's next?
-
-* Explore live Hydra GraphQL server [playground](https://hakusama.joystream.app/graphql) and query historical Kusama Treasury proposals 
-* [Install](install-hydra.md) Hydra toolkit 
-* Hydra [tutorial](quick-start.md): spin a Hydra Indexer and GraphQL server in under five minutes
-* Look at the [examples](../examples/) 
-* Learn how to define your own data [schema](schema-spec/) and [mappings](mappings/) to run a Hydra Indexer
-

+ 0 - 19
query-node/docs/architecture.md

@@ -1,19 +0,0 @@
----
-description: A more in-depth look at how Hydra works under the hood
----
-
-# Architecture
-
-A Hydra query node consists of the following core parts:
-
-* Blockchain Indexer
-* PostgreSQL \(Data Storage\)
-* GraphQL Server
-* GraphQL-like data [schema](https://github.com/dzhelezov/joystream/tree/f07cb27a73ec74292811648cee8a92d8fab3b6c9/query-node/docs/schema.md) & event [mappings](https://github.com/dzhelezov/joystream/tree/f07cb27a73ec74292811648cee8a92d8fab3b6c9/query-node/docs/mappings.md)
-
-Hydra takes as an input a high-level GraphQL-like schema modeling the blockchain data \("entities"\) to be indexed. The mappings describe the event handlers telling the indexer how the blockchain events affect the schema entities.
-
-Once the schema and the mappings are set up, the Indexer prepares the database and starts the continuous scan of the blockchain, processing the events through the mappings and updating the entities in the database.
-
-The GraphQL Server is a separate web server providing a [GraphQL](https://graphql.org/) API for the entities in the data store. The API requests are resolved by the server into database queries, providing quick access to the most recent state of the entities. OpenCRUD filtering, entity relations, pagination, and text queries are supported out-of-the-box by the API.
-

+ 0 - 140
query-node/docs/entity-relationship.md

@@ -1,140 +0,0 @@
-# GraphQL Entity Relationships
-
-### One-To-One (1:1) Relationships
-
-In One-To-One relation, one entity instance is related to only one instance of another entity. One side of the relationship should always derive.
-
-```graphql
-type User @entity {
-	name: String!
-	profile: Profile! @derivedFrom(field: "user")
-}
-
-type Profile @entity {
-	avatar: String!
-	user: User!
-}
-```
-
-Database tables:
-
-```
-          user
-| Column  | Type
-----------|-------
-| id      | character varying
-| name    | character varying
-```
-
-```
-          profile
-| Column  | Type
-----------|-------
-| id      | character varying
-| avatar  | character varying
-| userId  | character varying FOREIGN KEY UNIQUE CONSTRAINT
-```
-
-### One-To-Many (1:n) Relationships
-
-In One-To-Many relation, one entity instance is related to multiple instance of the other entity.
-
-```graphql
-type User @entity {
-	name: String
-}
-
-type Post @entity {
-	title: String
-	author: User!
-}
-```
-
-Database table for the `Post` entity:
-
-```
-          post
-| Column  | Type
-----------|-------
-| id      | character varying
-| avatar  | character varying
-| authorId  | character varying FOREIGN KEY
-```
-
-The only difference between `1:1` and `1:n` is the unique constraint that `1:1` has.
-
-### Many-To-Many (n:n) Relationships
-
-Many-To-Many is a relationship where one entity instance is related to many instance of other entity and vice-versa. In this relationship one side of the relation must derive.
-
-```graphql
-type User @entity {
-	name: String
-	books: [Book!] @derivedFrom(field: "authors")
-}
-
-type Book @entity {
-	title: String
-	authors: [User!]
-}
-```
-
-A junction table is created for n:n relationship.
-
-Database tables:
-
-```
-          book
-| Column  | Type
-----------|-------
-| id      | character varying
-| title   | character varying
-```
-
-```
-          book_user
-| Column  | Type
-----------|-------
-| book_id | character varying
-| user_id | character varying
-```
-
-### Reverse Lookups
-
-Defining reverse lookups on an entity allows you to query other side of the relation. Use `@derivedFrom` directive to add reverse lookup to an entity.
-
-**Example**
-If we want to access a user's `posts` from the user entity we should add a derived field to `User` entity:
-
-```graphql
-type User @entity {
-	name: String
-	posts: [Post!] @derivedField(field: "author")
-}
-
-type Post @entity {
-	title: String
-	author: User!
-}
-```
-
-## Relationships In Mappings
-
-Each GraphQL entity has a corresponding typeorm entity and we use these entities to perform CRUD operations.
-
-**Example**
-
-We will create a new post for an existing user:
-
-```ts
-export async function handleNewPost(db: DB, event: SubstrateEvent) {
-	const { userId, title } = event.params;
-	const user = await db.get(User, { where: { id: userId } });
-
-	const newPost = new Post();
-	newPost.title = title;
-	newPost.author = user;
-
-	db.save<Post>(newPost);
-}
-```

+ 0 - 0
query-node/docs/indexer.md


+ 0 - 53
query-node/docs/install-hydra.md

@@ -1,53 +0,0 @@
-# Install Hydra
-
-## Prerequisites
-
-* Both Hydra-CLI and the generated project files have dependencies that require Node v10.16 or higher
-* `npm` and \(optional, but recommended\) [`npx`](https://www.npmjs.com/package/npx)
-* Hydra stores the substrate data in an external PostgresSQL 12 instance. The scaffolding tool provides a convenient shortcut for running the database instance from a Docker image. In this case the standard docker environment \(`docker` and `docker-compose`\) should be available.
-* \(Optional\) [Docker engine](https://docs.docker.com/engine/install/). The scaffolding tool provides targets for building Docker images for external deployment.
-
-## Installation
-
-{% hint style="warning" %}
-The npm repository and the`hydra-cli`version will likely change in the near future. In such a case simply replace `@dzlzv/hydra-cli`with`<npm_repo>/hydra-cli@<version>` in the instructions below ``
-{% endhint %}
-
-_Global installation:_
-
-```bash
-npm install -g @dzlzv/hydra-cli
-```
-
-The path to `hydra-cli` binaries will be added to the system-wide `$PATH`.
-
-_Local installation:_
-
-```bash
-npm install @dzlzv/hydra-cli
-```
-
-The binaries will be installed to the local `.bin` folder. You can execute `hydra-cli` commands by adding the`.bin`folder within your local `node_modules` to `$PATH`.
-
-_Isolated set-up:_
-
-Execute `hydra-cli` commands directly by typing
-
-```bash
-npx @dzlzv/hydra-cli <command>
-```
-
-This provides an isolated way to execute `hydra-cli` commands. 
-
-{% hint style="success" %}
-Run `hydra-cli --version` to check your installation
-{% endhint %}
-
-{% hint style="info" %}
-It may be convenient to create an alias for quick access to `hydra-cli` e.g.
-
-```text
-alias hydra-cli='npx @dzlzv/hydra-cli'
-```
-{% endhint %}
-

+ 0 - 73
query-node/docs/manifest-spec.md

@@ -1,73 +0,0 @@
-# Query Node Manifest
-
-## Overview
-
-The query node manifest specifies the extract-transform-load processes run by a query node. A query
-node ingests raw events and data from a substrate chain and transforms and loads to the downstream
-_sink_ sources as specified by the manifest. The manifest loosely follows the subgraph manifest of by the graph protocol.
-
-## Top Level API
-
-| Field  | Type | Description   |
-| --- | --- | --- |
-| **specVersion** | *String*   | A Semver version indicating which version of this API is being used.|
-| **description** | *String* | An optional description of the substrate chain. |
-| **repository**  | *String* | An optional link to where the subgraph lives. |
-| **dataSources** | Data Source Spec | Each data source spec defines the data that will be ingested |
-| **schema**   | [*String*] | Path to the GraphQL schema augmented with directives supporting e.g. elasticsearch indices |
-
-## Schema
-
-Schema is a GraphQL spec
-
-## Data Source
-
-| Field | Type | Description |
-| --- | --- | --- |
-| **kind** | *String* | The type of data source. Possible values: *substrate/index*.|
-| **name** | *String* | The name of the source data. Will be used to generate APIs in the mapping and also for self-documentation purposes. |
-| **network** | *String* | For blockchains, this describes which network the subgraph targets. For substrate network, this should specify substrate network name, e.g. 'joystream/constaninople' |
-| **source** | [*Source*] | The source data on a substrate blockchain. |
-| **startBlock** | integer | Block height to start from |
-
-### Mapping
-
-The `mapping` field may be one of the following supported mapping manifests:
-
-| Field | Type | Description |
-| --- | --- | --- |
-| **kind** | *String* | Must be "substrate/bootstrap" for Substrate Bootstrap Mapping. |
-| **apiVersion** | *String* | Semver string of the version of the Mappings API that will be used by the mapping script. |
-| **language** | *String* | The language of the runtime for the Mapping API. Possible values: *wasm/assemblyscript*. |
-| **file** | [*Path*](#16-path) | The path of the mapping script. |
-
-> **Note:** Each mapping is required to supply one or more handler type, available types: `EventHandler`, `CallHandler`, `BlockHandler` or `BootHandler`.
-
-#### BootHandler
-
-| Field | Type | Description |
-| --- | --- | --- |
-| **entity** | *String* | Entity that should be loaded
-| **handler** | *String* | Function name to be called
-
-#### EventHandler
-
-| Field | Type | Description |
-| --- | --- | --- |
-| **event** | *String* | An identifier for an event that will be handled in the mapping script. For Ethereum contracts, this must be the full event signature to distinguish from events that may share the same name. No alias types can be used. For example, uint will not work, uint256 must be used.|
-| **handler** | *String* | The name of an exported function in the mapping script that should handle the specified event. |
-| **topic0** | optional *String* | A `0x` prefixed hex string. If provided, events whose topic0 is equal to this value will be processed by the given handler. When topic0 is provided, _only_ the topic0 value will be matched, and not the hash of the event signature. This is useful for processing anonymous events in Solidity, which can have their topic0 set to anything.  By default, topic0 is equal to the hash of the event signature. |
-
-#### CallHandler
-
-| Field | Type | Description |
-| --- | --- | --- |
-| **function** | *String* | An identifier for a function that will be handled in the mapping script. For Ethereum contracts, this is the normalized function signature to filter calls by. |
-| **handler** | *String* | The name of an exported function in the mapping script that should handle the specified event. |
-
-#### BlockHandler
-
-| Field | Type | Description |
-| --- | --- | --- |
-| **handler** | *String* | The name of an exported function in the mapping script that should handle the specified event. |
-| **filter** | optional *String* | The name of the filter that will be applied to decide on which blocks will trigger the mapping. If none is supplied, the handler will be called on every block. |

+ 0 - 51
query-node/docs/mappings/README.md

@@ -1,51 +0,0 @@
----
-description: Mappings describe how Substate events should be handled by the indexer
----
-
-# Mappings
-
-A mapping file is a standalone typescript module defining how the Substrate events of interest should be handled by the Hydra indexer.
-
-The event handlers \(aka _mappings_\) should by convention be named `handle<EventName>` , so, for example, a handle for `trasury.Proposal` event should be named `handleProposal` 
-
-Each handler must have exactly two arguments exported by the Indexer: the `db` handle which gives access to the database and `SubstrateEvent` which contains all the necessary data extracted by the indexer from the Substrate chain.
-
-Let us look at the sample mapping generated by the scaffolder
-
-```typescript
-import { SubstrateEvent, DB } from '../generated/indexer';
-import { Proposal } from '../generated/graphql-server/src/modules/proposal/proposal.model';
-import { ProposalStatus } from '../generated/graphql-server/src/modules/enums/enums';
-import { assert } from 'console';
-import * as BN from 'bn.js';
-
-// New proposal
-export async function handleProposed(db: DB, event: SubstrateEvent) {
-  const { ProposalIndex } = event.event_params;
-  if (event.extrinsic) {
-    const proposal = new Proposal();
-    proposal.proposalIndex = new BN(ProposalIndex.toString());
-    proposal.value = new BN(event.extrinsic.args[0].toString());
-    proposal.bond = new BN(event.extrinsic.args[0].toString());
-    proposal.beneficiary = Buffer.from(event.extrinsic.args[1].toString());
-    proposal.proposer = Buffer.from(event.extrinsic.signer.toString());
-    proposal.status = ProposalStatus.NONE;
-
-    await db.save<Proposal>(proposal);
-  }
-}
-```
-
-Note that required entity classes are exported from 
-
-```text
-../generated/graphql-server/src/modules/<entity type>/<entity type>
-```
-
-and this is where all the auto-generated classes live by default.
-
-Next, the body of the handler transforms the event parameters and extrinsic arguments into the properties of the entity. There is currently no way to enforce type safety here and one should instead inspect the event parameters and extrinsics for the event in question. In the example above, we can consult the Kusama [explorer](https://kusama.subscan.io/extrinsic/0x1bba67ddb62117fc64710e35b6ccbef64d4df528d78310ccca725137e75823d4?event=2022835-5) and check that 
-
-* `ProposalIndex` is a single named param of `treasury.Proposed` event
-* The extrinsic has to arguments: `value` and `beneficiary`, propagated to the entity in a straightforward fashion.
-

+ 0 - 41
query-node/docs/mappings/databasemanager.md

@@ -1,41 +0,0 @@
----
-description: A closer look at the database handle passed as a first argument to the mappers
----
-
-# DatabaseManager
-
-The database handler is a proxy for the DatabaseManager and incapsulates the standard CRUD database operations:
-
-```typescript
-/**
- * Database access interface. Use typeorm transactional entity manager to perform get/save/remove operations.
- */
-export default interface DatabaseManager {
-  /**
-   * Save given entity instance, if entity is exists then just update
-   * @param entity
-   */
-  save<T>(entity: DeepPartial<T>): Promise<void>;
-
-  /**
-   * Removes a given entity from the database.
-   * @param entity: DeepPartial<T>
-   */
-  remove<T>(entity: DeepPartial<T>): Promise<void>;
-
-  /**
-   * Finds first entity that matches given options.
-   * @param entity: T
-   * @param options: FindOneOptions<T>
-   */
-  get<T>(entity: { new (...args: any[]): T }, options: FindOneOptions<T>): Promise<T | undefined>;
-
-  /**
-   * Finds entities that match given options.
-   * @param entity: T
-   * @param options: FindOneOptions<T>
-   */
-  getMany<T>(entity: { new (...args: any[]): T }, options: FindOneOptions<T>): Promise<T[]>;
-}
-```
-

+ 0 - 31
query-node/docs/mappings/substrateevent.md

@@ -1,31 +0,0 @@
----
-description: >-
-  Interface containing the required information about the emitted Substrate
-  event
----
-
-# SubstrateEvent
-
-The`SubstrateEvent` object is passed as the second argument for each event handler and contains all the essential information about the event being processed by Hydra Indexer. Let us take a closer look at the interface. 
-
-```typescript
-import { Extrinsic } from '@polkadot/types/interfaces';
-import { Codec } from '@polkadot/types/types';
-import * as BN from 'bn.js';
-
-interface EventParameters {
-  [key: string]: Codec;
-}
-
-export interface SubstrateEvent {
-  event_name: string;
-  event_method: string;
-  event_params: EventParameters;
-  index: BN;
-  block_number: BN;
-  extrinsic?: Extrinsic;
-}
-```
-
-As can be seen above,  the key information about the event is encapsulated by the `Extrinsic` interface of the `@polkadot` libraries. Therefore, unfortunately, the actual data payload passed to the mappers highly depends on the event and the underlying Substrate chain. A more user-friendly and type-safe approach is in the works and will be introduced in the future versions of Hydra.
-

+ 0 - 106
query-node/docs/quick-start.md

@@ -1,106 +0,0 @@
----
-description: Build a Hydra Indexer and GraphQL server from scratch under five minutes
----
-
-# Tutorial
-
-{% hint style="info" %}
-Before starting, make sure`hydra-cli`is [installed](install-hydra.md) on your machine together with all the prerequisites. 
-{% endhint %}
-
-## 0. Hello Hydra!
-
-Start off by setting up a project folder
-
-```bash
-mkdir hello-hydra && cd hello-hydra
-```
-
-## 1. From zero to one
-
-Next, run the scaffold command, which generates all the required files:
-
-```bash
-hydra-cli scaffold
-```
-
-Answer the prompts and the scaffolder will generate a sample backbone for our Hydra project. This includes:
-
-* Sample GraphQL data [schema](schema-spec/) in `schema.graphql` describing proposals in the Kusama network
-* Sample [mapping](mappings/) scripts in the `./mapping` folder translating substrate events into the `Proposal` entity CRUD operations
-* `docker-compose.yml` for running a Postgres instance locally as a Docker service.
-* `.env` with all the necessary environment variables.
-* `package.json` with a few utility yarn scripts to be used later on.
-
-## 2. Codegen
-
-Now all is set for generating the Graphql server and the indexer for Kusama proposals:
-
-```bash
-hydra-cli codegen
-```
-
-The codegen command creates two separate projects:
-
-* `./generated/graphql-server`: this is a GraphQL for querying the proposals
-* `./generated/indexer`: this is a background indexer tool that fetches the blocks from the Substrate chain \(in this case the public Kusama network\) and updates the database calling the mapping scripts
-
-## 3. Set up the database
-
-Now it's time to set up the database:
-
-```bash
-yarn db:start
-```
-
-This command simply spins up a Postgres Docker image.
-
-```bash
-yarn db:bootstrap
-```
-
-This creates a DB schema for our data model described in `schema.graphql`.
-
-## 4. Start Hydra Indexer
-
-Finally, we're ready to run the indexer and the GraphQL server:
-
-```bash
-yarn indexer:start
-```
-
-Keep an eye on the output to keep track of the indexer's progress.
-
-## 5. Start Hydra GraphQL server
-
-In a separate terminal window:
-
-```bash
-yarn server:start:dev
-```
-
-The last command starts the server in the dev mode and you will see a GraphQL playground opening in your browser \(if not, navigate manually to `localhost:4000/graphql`\). It's time to explore all the GraphQL queries supported out-of-the-box! Note, that depending on the starting block it may take a considerable time for the indexer to catch up with the Kusama network, and until then queries may return empty results.
-
-## 6. Dockerize
-
-Among other things, the scaffolder generates a top-level `package.json`with a bunch of convenient `yarn` targets. For example, putting your Hydra Indexer and GraphQL server is easy as running the following targets:
-
-```bash
-yarn docker:indexer:build
-```
-
-```bash
-yarn docker:server:build
-```
-
-This will create Docker images named `hydra-indexer` and `hydra-graphql-server`
-
-## What to do next?
-
-* Explore more [examples](../examples/)
-* Describe your own [schema](schema-spec/) in `schema.graphql`
-* Write your indexer [mappings](mappings/)
-* Push your Hydra indexer and GraphQL Docker images to [Docker Hub](https://hub.docker.com/) and deploy  
-
-
-

+ 0 - 15
query-node/docs/schema-spec.md

@@ -1,15 +0,0 @@
-# Query Node schema
-
-## Overview
-
-The query node schema is a graphql schema file encriched with directives explained below.
-The schema is used by `cli codegen` in order to generate a GraphQL API server for quering the
-substrate blockchain data.
-
-## Entities
-
-TBD
-
-## Derivatives
-
-TBD

+ 0 - 16
query-node/docs/schema-spec/README.md

@@ -1,16 +0,0 @@
----
-description: >-
-  The schema file describes your domain objects, relationships and the supported
-  queries.
----
-
-# Schema
-
-## Overview
-
-Hydra input schema is a dialect of the GraphQL schema definition language enriched with the additional directives and built-in primitive types described in what follows. The input schema is consumed by `hydra-cli codegen` to generate the entity classes for the database and the final API GraphQL schema served by the server. The latter is auto-generated and can be previewed by running 
-
-```text
-$ hydra-cli preview && cat apipreview.graphql
-```
-

+ 0 - 51
query-node/docs/schema-spec/entities.md

@@ -1,51 +0,0 @@
----
-description: Entities is the backbone of the data model and translate into the db schema
----
-
-# Entities
-
-Entities are the top-level type definitions in the input schema marked with the `@entity` directive. Entity fields are normally built-in scalar types but can also be 
-
-* an array of a primitive types
-* an [enum](enums.md),
-* an [entity reference](entity-relationship.md)
-* an [algebraic type ](variant-types.md)
-
-All entities have an auto-generated `ID` field which is reserved and cannot be used in the input schema.
-
-### Primitive types
-
-The following scalar types are supported:
-
-* `Boolean`
-* `String`
-* `Int`
-* `Float`
-* `BigInt` supports arbitrarily large numbers and is useful for representing e.g. large numbers `uint256`
-* `Bytes`
-
-Arrays follow the GraphQL [spec](https://spec.graphql.org/June2018/).
-
-### Modifiers and decorators 
-
-By default, each field is nullable. To indicate a no-null constraint mark the field with `!`
-
-If a property must be unique across all entities of the given type, mark it with a built-in `@unique` directive
-
-Schema comments are natively supported and are propagated to the output schema
-
-### Example
-
-```graphql
-"It is just a boring nine-five person"
-type Person @entity {
-    name: String!
-    married: Boolean
-    age: Int
-    "one person, one account, one live"
-    account: Bytes! @unique
-    salary: BigInt
-    interests: [String]
-}
-```
-

+ 0 - 144
query-node/docs/schema-spec/entity-relationship.md

@@ -1,144 +0,0 @@
----
-description: 'Define one-to-one, one-to-many and many-to-many relationships between entities'
----
-
-# Entity Relationships
-
-### One-To-One \(1:1\) Relationships
-
-In One-To-One relation, one entity instance is related to only one instance of another entity. One side of the relationship should always derive.
-
-```graphql
-type User @entity {
-    name: String!
-    profile: Profile! @derivedFrom(field: "user")
-}
-
-type Profile @entity {
-    avatar: String!
-    user: User!
-}
-```
-
-Database tables:
-
-```text
-          user
-| Column  | Type
-----------|-------
-| id      | character varying
-| name    | character varying
-```
-
-```text
-          profile
-| Column  | Type
-----------|-------
-| id      | character varying
-| avatar  | character varying
-| userId  | character varying FOREIGN KEY UNIQUE CONSTRAINT
-```
-
-### One-To-Many \(1:n\) Relationships
-
-In One-To-Many relation, one entity instance is related to multiple instances of the other entity.
-
-```graphql
-type User @entity {
-    name: String
-}
-
-type Post @entity {
-    title: String
-    author: User!
-}
-```
-
-Database table for the `Post` entity:
-
-```text
-          post
-| Column  | Type
-----------|-------
-| id      | character varying
-| avatar  | character varying
-| authorId  | character varying FOREIGN KEY
-```
-
-The only difference between `1:1` and `1:n` is the unique constraint that `1:1` has.
-
-### Many-To-Many \(n:n\) Relationships
-
-Many-To-Many is a relationship where one entity instance is related to a collection of instances of other entities and vice-versa. In this relationship, one side of the relation must derive.
-
-```graphql
-type User @entity {
-    name: String
-    books: [Book!] @derivedFrom(field: "authors")
-}
-
-type Book @entity {
-    title: String
-    authors: [User!]
-}
-```
-
-A junction table is created for n:n relationship.
-
-Database tables:
-
-```text
-          book
-| Column  | Type
-----------|-------
-| id      | character varying
-| title   | character varying
-```
-
-```text
-          book_user
-| Column  | Type
-----------|-------
-| book_id | character varying
-| user_id | character varying
-```
-
-### Reverse Lookups
-
-Defining reverse lookups on an entity allows you to query the other side of the relation. Use `@derivedFrom` directive to add a reverse lookup to an entity.
-
-**Example** If we want to access a user's `posts` from the user entity we should add a derived field to `User` entity:
-
-```graphql
-type User @entity {
-    name: String
-    posts: [Post!] @derivedField(field: "author")
-}
-
-type Post @entity {
-    title: String
-    author: User!
-}
-```
-
-## Relationships In Mappings
-
-Each GraphQL entity has a corresponding TypeORM entity and we use these entities to perform CRUD operations.
-
-**Example**
-
-We will create a new post for an existing user:
-
-```typescript
-export async function handleNewPost(db: DB, event: SubstrateEvent) {
-    const { userId, title } = event.params;
-    const user = await db.get(User, { where: { id: userId } });
-
-    const newPost = new Post();
-    newPost.title = title;
-    newPost.author = user;
-
-    db.save<Post>(newPost);
-}
-```
-

+ 0 - 17
query-node/docs/schema-spec/enums.md

@@ -1,17 +0,0 @@
-# Enums
-
-Enums are natively supported as described the GraphQL schema [spec](https://spec.graphql.org/June2018/#sec-Enums). Here is an illustrative example:
-
-```text
-enum {
-  NONE
-  REJECTED
-  APPROVED
-}
-
-type Proposal @entity {
-  status: ProposalStatus
-  bond: BigInt!
-}
-```
-

+ 0 - 55
query-node/docs/schema-spec/full-text-queries.md

@@ -1,55 +0,0 @@
----
-description: Run cross-field and cross-entity full-text queries
----
-
-# Full-text queries
-
-Full-text queries are able to search across a large amount of text data and aggregate the results across multiple fields and even entities. The query output provides the result rank and a highlight if there is a text match. 
-
-In order to enable full-text search queries in the API, decorate any number of `String`fields with `@fulltext(query: <query_name>)` decorator, like this:
-
-```graphql
-type Post @entity{
-   title: String @fulltext(query: "forum"),
-   body: String @fulltext(query: "forum")
-}
-
-type Comment @entity {
-   text: String @fulltext(query: "forum")
-}
-```
-
-The generated output schema will define the required output type and the query:
-
-```graphql
-type SearchResult {
-   item: Post | Comment,
-   rank: number, 
-   highligt: String
-}
-
-type Query {
-   forum(text: String, limit?: Int): SearchResult[]
-}
-```
-
-One can now run similarity query:
-
-```graphql
-query {
-   forum(text: "some partially matching text", limit: 5) {
-      rank
-      highlight 
-      item {
-         ... on Post {
-            body
-         }
-         ... on Comment {
-            title
-         }
-      }
-       
-   }
-}
-```
-

+ 0 - 43
query-node/docs/schema-spec/interfaces.md

@@ -1,43 +0,0 @@
----
-description: Extract interfaces and query multiple types in a single query
----
-
-# Interfaces
-
-Interfaces are useful when several entity types share some set of properties and one would like to have an aggregated result when such a common property is queried.
-
-This is achieved through the natively supported GraphQL [interface](https://graphql.org/learn/schema/#interfaces) type and [inline fragments](https://graphql.org/learn/queries/#inline-fragments) in the output schema. For example, let us define the following input schema:
-
-```graphql
-interface Profile {
-    about: String!
-}
-
-type Member implements About @entity {
-    about: String!
-    handle: String!
-}
-
-type Account implements Abount @entity {
-    about: String!
-    accountId: Bytes   
-}
-```
-
-The output schema will support a query by `about` which puts together `Member` and `Account` types. Note that `orderBy` is also supported for the inherited properties as well as OpenCRUD.
-
-```graphql
-query {
-  profiles(limit: 5, offset: 5, orderBy: about_ASC, where: { about_eq: "joystreamer" }) {
-    about
-    __typename 
-    ... on Member {
-      handle
-    }
-    ... on Account {
-      accountId
-    }
-  }
-}
-```
-

+ 0 - 57
query-node/docs/schema-spec/the-query-goodies.md

@@ -1,57 +0,0 @@
----
-description: >-
-  The output schema automatically supports OpenCRUD filtering, pagination and
-  ordering
----
-
-# The Goodies
-
-### Filtering
-
-All the scalar entity types enjoy first-class support in the output schema when it comes to filtering. The standard is known as [OpenCRUD](https://www.opencrud.org/) and dictates who filtering should look like depending on the field type. For example, if the input schema defines the following type:
-
-```graphql
-type Person @entity {
-    name: String!
-    married: Boolean
-    age: Int
-    account: Bytes! @unique
-    salary: BigInt
-    interests: [String]
-}
-```
-
-the output schema will support the following query:
-
-```text
-query {
-    persons(where: { name_startsWith: "Joh", age_gt: 20 }) {
-      name
-    }
-}
-```
-
-### Pagination
-
-All queries enjoy support of pagination by accepting `offset` and `limit` input parameters. By default, `limit` is set to 5.
-
-```graphql
-query {
-    persons(offset: 10, limit: 5) {
-      name
-    }
-}
-```
-
-### Ordering
-
-The results can also be ordered by any property with natural ordering. `_DESC`an  `_ASC` suffixes indicate the direction:
-
-```graphql
-query {
-    persons(offset: 10, limit: 5, orderBy: name_ASC) {
-      name
-    }
-}
-```
-

+ 0 - 54
query-node/docs/schema-spec/variant-types.md

@@ -1,54 +0,0 @@
-# Algebraic types
-
-One can construct complex types by defining unions of special non-entity type definitions decorated with `@variant`. The resulting complex type is mapped into JSON at the database level and should be prefixed with `_json` in when queried through the API. Here is an example
-
-```graphql
-type Miserable @variant {
-  hates: String!
-}
-
-type HappyPoor @variant {
-  isMale: boolean
-}
-
-union Poor = HappyPoor | Miserable
-
-type MiddleClass @variant {
-  father: Poor
-  mother: Poor
-}
-
-type Rich @variant {
-  bank: EntityC
-}
-
-union Status = Poor | MiddleClass | HappyPoor | Miserable
-
-type Account @entity {
-  status: Status!
-}
-```
-
-The resulting API will support [inline fragments](https://graphql.org/learn/schema/#union-types) and type resolutions:
-
-```graphql
-query {
-	accounts(limit: 5, orderBy: about_ASC, where: { status_json: { father: { isMale_eq: true }} }) {
-    about
-    status {
-      __typename 
-      ... on MiddleClass {
-        father {
-          ... on HappyPoor {
-            isMale
-          }
-          ... on Miserable {
-            hates
-          }
-        }
-      }
-    }
-  }
-}
-```
-

+ 0 - 2
query-node/examples/README.md

@@ -1,2 +0,0 @@
-# examples
-

+ 0 - 2
query-node/examples/kusama-query-node.md

@@ -1,2 +0,0 @@
-# kusama-query-node
-

+ 0 - 11
query-node/examples/kusama-query-node/.env

@@ -1,11 +0,0 @@
-WS_PROVIDER_ENDPOINT_URI=wss://kusama-rpc.polkadot.io/
-QUERY_NODE_BOOTSTRAP_DB=true
-BOOTSTRAP_PACK_LOCATION=../../bootstrap
-DB_NAME=query_node
-BLOCK_HEIGHT=3212286
-DB_USER=postgres
-DB_PASS=postgres
-DB_HOST=localhost
-DB_PORT=5432
-GRAPHQL_SERVER_PORT=4000
-DEBUG=index-builder:*

+ 0 - 1
query-node/examples/kusama-query-node/README.md

@@ -1 +0,0 @@
-# kusama-query-node

BIN
query-node/examples/kusama-query-node/mappings/.DS_Store


+ 0 - 1
query-node/examples/kusama-query-node/mappings/index.ts

@@ -1 +0,0 @@
-export * from './treasury';

+ 0 - 2
query-node/examples/kusama-query-node/mappings/treasury/index.ts

@@ -1,2 +0,0 @@
-export * from './proposal';
-export * from './tip';

+ 0 - 47
query-node/examples/kusama-query-node/mappings/treasury/proposal.ts

@@ -1,47 +0,0 @@
-import { SubstrateEvent, DB } from '../../generated/indexer';
-import { Proposal } from '../../generated/graphql-server/src/modules/proposal/proposal.model';
-import { ProposalStatus } from '../../generated/graphql-server/src/modules/enums/enums';
-import { assert } from 'console';
-import * as BN from 'bn.js';
-
-// New proposal
-export async function treasuryProposed(db: DB, event: SubstrateEvent) {
-  const { ProposalIndex } = event.event_params;
-  if (event.extrinsic) {
-    const proposal = new Proposal();
-    proposal.proposalIndex = new BN(ProposalIndex.toString());
-    proposal.value = new BN(event.extrinsic?.args[0].toString());
-    proposal.bond = new BN(event.extrinsic?.args[0].toString());
-    proposal.beneficiary = Buffer.from(event.extrinsic?.args[1].toString());
-    proposal.proposer = Buffer.from(event.extrinsic?.signer.toString());
-    proposal.status = ProposalStatus.NONE;
-
-    await db.save<Proposal>(proposal);
-  }
-}
-
-// A proposal was rejected
-export async function treasuryRejected(db: DB, event: SubstrateEvent) {
-  const { ProposalIndex } = event.event_params;
-  const proposal = await db.get(Proposal, { where: { proposalIndex: ProposalIndex.toString() } });
-
-  assert(proposal, 'Proposal not found! Invalid proposal id');
-
-  if (proposal) {
-    proposal.status = ProposalStatus.REJECTED;
-    await db.save<Proposal>(proposal);
-  }
-}
-
-// A proposal is approved! Some funds have been allocated.
-export async function treasuryAwarded(db: DB, event: SubstrateEvent) {
-  const { ProposalIndex } = event.event_params;
-  const proposal = await db.get(Proposal, { where: { proposalIndex: ProposalIndex.toString() } });
-
-  assert(proposal, 'Proposal not found! Invalid proposal id');
-
-  if (proposal) {
-    proposal.status = ProposalStatus.APPROVED;
-    await db.save<Proposal>(proposal);
-  }
-}

+ 0 - 77
query-node/examples/kusama-query-node/mappings/treasury/tip.ts

@@ -1,77 +0,0 @@
-import { DB, SubstrateEvent } from '../../generated/indexer';
-import { Tip } from '../../generated/graphql-server/src/modules/tip/tip.model';
-import { Tipper } from '../../generated/graphql-server/src/modules/tipper/tipper.model';
-import { assert } from 'console';
-import * as BN from 'bn.js';
-
-export async function treasuryNewTip(db: DB, event: SubstrateEvent) {
-  const { Hash } = event.event_params;
-  const { extrinsic } = event;
-
-  if (extrinsic) {
-    const tip = new Tip();
-    tip.reason = Buffer.from(Hash.toString());
-    tip.who = Buffer.from(extrinsic.args[1]);
-    tip.retracted = false;
-    tip.finder = Buffer.from(extrinsic?.signer.toString());
-
-    const runtimeFuncName = extrinsic.meta.name.toString();
-    // check runtime function name that emit the event
-    tip.findersFee = runtimeFuncName === 'report_awesome';
-
-    db.save<Tip>(tip);
-
-    // NewTip event can be fired from different runtime functions
-    if (runtimeFuncName !== 'report_awesome') {
-      //Give a tip for something new; no finder's fee will be taken.
-      const t = new Tipper();
-      t.tipValue = new BN(extrinsic.args[2].toString());
-      t.tipper = Buffer.from(extrinsic?.signer.toString());
-      t.tip = tip;
-      db.save<Tipper>(t);
-    }
-  }
-}
-
-export async function treasuryTipRetracted(db: DB, event: SubstrateEvent) {
-  const { Hash } = event.event_params;
-  const tip = await db.get(Tip, { where: { reason: Buffer.from(Hash.toString()) } });
-
-  assert(tip, 'Invalid reason hash!');
-  if (tip) {
-    tip.retracted = true;
-    db.save<Tip>(tip);
-  }
-}
-
-// A tip suggestion has reached threshold and is closing.
-export async function treasuryTipClosing(db: DB, event: SubstrateEvent) {
-  const { Hash } = event.event_params;
-  const { extrinsic } = event;
-  const tip = await db.get(Tip, { where: { reason: Buffer.from(Hash.toString()) } });
-
-  assert(tip, 'Invalid reason hash!');
-  if (tip && extrinsic) {
-    const t = new Tipper();
-    t.tipper = Buffer.from(extrinsic?.signer.toString());
-    t.tipValue = new BN(extrinsic.args[1].toString());
-    t.tip = tip;
-    db.save<Tipper>(t);
-
-    tip.closes = new BN(event.block_number.toString());
-    db.save<Tip>(tip);
-  }
-}
-
-// A tip suggestion has reached threshold and is closing.
-export async function treasuryTipClosed(db: DB, event: SubstrateEvent) {
-  const { Hash, AccountId } = event.event_params;
-  const { extrinsic } = event;
-  const tip = await db.get(Tip, { where: { reason: Buffer.from(Hash.toString()) } });
-
-  assert(tip, 'Invalid reason hash!');
-
-  if (tip && extrinsic) {
-    tip.who = Buffer.from(AccountId.toString());
-  }
-}

+ 0 - 11
query-node/examples/kusama-query-node/package.json

@@ -1,11 +0,0 @@
-{
-  "name": "kusama-query-node",
-  "version": "1.0.0",
-  "main": "index.js",
-  "license": "MIT",
-  "dependencies": {
-    "@types/bn.js": "^4.11.6",
-    "bn.js": "^5.1.2",
-    "tslib": "^2.0.0"
-  }
-}

+ 0 - 57
query-node/examples/kusama-query-node/schema.graphql

@@ -1,57 +0,0 @@
-enum ProposalStatus {
-  NONE
-  REJECTED
-  APPROVED
-}
-
-"A spending proposal"
-type Proposal @entity {
-  "The account proposing it"
-  proposer: Bytes!
-
-  "The (total) amount that should be paid if the proposal is accepted"
-  value: BigInt!
-
-  "The account to whom the payment should be made if the proposal is accepted"
-  beneficiary: Bytes!
-
-  "The amount held on deposit (reserved) for making this proposal"
-  bond: BigInt!
-
-  proposalIndex: BigInt! @unique
-
-  status: ProposalStatus
-}
-
-"The members who have voted for the tip."
-type Tipper @entity {
-  tip: Tip!
-  tipper: Bytes!
-  tipValue: BigInt!
-}
-
-type Tip @entity {
-  "The hash of the reason for the tip."
-  reason: Bytes! @unique
-
-  "The account to be tipped."
-  who: Bytes!
-
-  "The account who began this tip."
-  finder: Bytes!
-
-  "The amount held on deposit for this tip."
-  deposit: BigInt
-
-  "The block number at which this tip will close if Some."
-  closes: BigInt
-
-  "The members who have voted for this tip."
-  tippers: [Tipper!] @derivedFrom(field: "tip")
-
-  "Whether this tip should result in the finder taking a fee."
-  findersFee: Boolean!
-
-  "Cancel the process of tipping"
-  retracted: Boolean!
-}

+ 0 - 145
query-node/joystream-query-node.md

@@ -1,145 +0,0 @@
-# Joystream Query Node
-
-Joystream query node can be generated by using `substrate-query-node/cli`.
-
-## Getting Started
-
-Cli create a folder named `generated` and put everthing inside it.
-
-```text
-$ cli codegen
-```
-
-Start graphql server:
-
-```text
-$ cd generated/graphql-server
-$ yarn start:dev
-```
-
-Start block indexer:
-
-```text
-$ cd generated/indexer
-$ yarn start
-```
-
-## Add a new mapping for Joystream MemberRegistered event
-
-1. Every mapping function get a parameter of `DB` type
-
-```typescript
-import { DB } from '../generated/indexer';
-```
-
-1. `db` object is for database operations save/get/remove and access to event itself
-2. Define the event handler function with the following signature and import the entity class
-
-```typescript
-import { MemberRegistereds } from '../generated/indexer/entities/MemberRegistereds';
-export async function handleMemberRegistered(db: DB) {}
-```
-
-1. Inside the handler function create a new instance of the entity and fill properties with event data.
-
-```typescript
-// Get event data
-const { AccountId, MemberId } = db.event.event_params;
-const member = new MemberRegistereds({ accountId: AccountId.toString(), memberId: +MemberId });
-```
-
-1. Call `db.save()` method to save data on database
-
-```typescript
-// Save to database.
-db.save<MemberRegistereds>(member);
-```
-
-1. Query database
-
-```typescript
-// Query from database
-const findOptions = { where: { memberId: 123 } }; // match the record
-const m = await db.get(MemberRegistereds, findOptions);
-```
-
-Below you can find the complete code
-
-**Complete code**
-
-```typescript
-import { MemberRegistereds } from "../generated/indexer/entities/MemberRegistereds";
-import { DB } from "../generated/indexer";
-
-export async function handleMemberRegistered(db: DB) {
-  // Get event data
-  const { AccountId, MemberId } = db.event.event_params;
-
-  const member = new MemberRegistereds({ accountId: AccountId.toString(), memberId: +MemberId };
-
-  // Save to database.
-  db.save<MemberRegistereds>(member);
-
-  // Query from database
-  const m = await db.get(MemberRegistereds, { where: { memberId: 123 } });
-}
-```
-
-## Query Node Constructs Explained
-
-1. `schema.graphql` is where you define types for graphql server. Graphql server use these types to generate db models, db tables, graphql resolvers.
-
-Below you can find a type defination example:
-
-```graphql
-type Membership {
-  # Member's root account id
-  accountId: String!
-
-  # Member's id
-  memberId: Int!
-
-  # The unique handle chosen by member
-  handle: String
-
-  # A Url to member's Avatar image
-  avatarUri: String
-
-  # Short text chosen by member to share information about themselves
-  about: String
-}
-```
-
-**Important** Relationship between types not supported yet!
-
-1. Block indexer is block consumer and every block can have events that we want to store their data. So indexing data from events we need to send the event to a function or a class that can handle the event and stores the event data on the database. `mappings` are the functions that we use to update our database with events data. Functions that we define in our mappings will be called only when the event name match our function name \(function name pattern is `'handle' + eventName`\). We call mapping functions as event handlers. Each event handler have only one parameter which is the `db: DB`. Every database operation is made with `db` object and the event can be accessed with `db` object. Below you can find an example for the event a handler:
-
-```typescript
-// mappings/index.ts
-
-import { DB } from '../generated/indexer';
-
-export function handleMemberRegistered(db: DB) {
-  console.log(`Event parameters: ${db.event.event_params}`);
-}
-```
-
-1. Block indexer connects to a blockchain node via WebSocket so we need to tell block indexer where to find the address of the node. Also, on the initialization of the indexer, we must pass the type register function as a parameter. So we put these variables inside the `.env` file that indexer can find and use them. For Joystream we will be running a local development node and add the name of the function, the package for the type registration:
-
-```text
-WS_PROVIDER_ENDPOINT_URI=ws://localhost:9944
-TYPE_REGISTER_PACKAGE_NAME=@joystream/types
-TYPE_REGISTER_FUNCTION=registerJoystreamTypes
-```
-
-1. Database connections options are defined in `.env`:
-
-```text
-DB_NAME=test
-DB_USER=postgres
-DB_PASS=postgres
-DB_HOST=localhost
-DB_PORT=5432
-GRAPHQL_SERVER_PORT=4000
-```
-

+ 0 - 12
query-node/joystream-query-node/.env

@@ -1,12 +0,0 @@
-WS_PROVIDER_ENDPOINT_URI=ws://localhost:9944
-QUERY_NODE_BOOTSTRAP_DB=true
-BOOTSTRAP_PACK_LOCATION=../../bootstrap
-TYPE_REGISTER_PACKAGE_NAME=@joystream/types
-TYPE_REGISTER_FUNCTION=registerJoystreamTypes
-DB_NAME=query_node
-DB_USER=postgres
-DB_PASS=postgres
-DB_HOST=localhost
-DB_PORT=5432
-GRAPHQL_SERVER_PORT=4000
-DEBUG=index-builder:*

+ 0 - 145
query-node/joystream-query-node/README.md

@@ -1,145 +0,0 @@
-# Joystream Query Node
-
-Joystream query node can be generated by using `substrate-query-node/cli`.
-
-## Getting Started
-
-Cli create a folder named `generated` and put everthing inside it.
-
-```
-$ cli codegen
-```
-
-Start graphql server:
-
-```
-$ cd generated/graphql-server
-$ yarn start:dev
-```
-
-Start block indexer:
-
-```
-$ cd generated/indexer
-$ yarn start
-```
-
-## Add a new mapping for Joystream MemberRegistered event
-
-1. Every mapping function get a parameter of `DB` type
-
-```ts
-import { DB } from '../generated/indexer';
-```
-
-2. `db` object is for database operations save/get/remove and access to event itself
-
-3. Define the event handler function with the following signature and import the entity class
-
-```ts
-import { MemberRegistereds } from '../generated/indexer/entities/MemberRegistereds';
-export async function handleMemberRegistered(db: DB) {}
-```
-
-4. Inside the handler function create a new instance of the entity and fill properties with event data.
-
-```ts
-// Get event data
-const { AccountId, MemberId } = db.event.event_params;
-const member = new MemberRegistereds({ accountId: AccountId.toString(), memberId: +MemberId });
-```
-
-5. Call `db.save()` method to save data on database
-
-```ts
-// Save to database.
-db.save<MemberRegistereds>(member);
-```
-
-6. Query database
-
-```ts
-// Query from database
-const findOptions = { where: { memberId: 123 } }; // match the record
-const m = await db.get(MemberRegistereds, findOptions);
-```
-
-Below you can find the complete code
-
-**Complete code**
-
-```ts
-import { MemberRegistereds } from "../generated/indexer/entities/MemberRegistereds";
-import { DB } from "../generated/indexer";
-
-export async function handleMemberRegistered(db: DB) {
-  // Get event data
-  const { AccountId, MemberId } = db.event.event_params;
-
-  const member = new MemberRegistereds({ accountId: AccountId.toString(), memberId: +MemberId };
-
-  // Save to database.
-  db.save<MemberRegistereds>(member);
-
-  // Query from database
-  const m = await db.get(MemberRegistereds, { where: { memberId: 123 } });
-}
-```
-
-## Query Node Constructs Explained
-
-1. `schema.graphql` is where you define types for graphql server. Graphql server use these types to generate db models, db tables, graphql resolvers.
-
-Below you can find a type defination example:
-
-```graphql
-type Membership {
-  # Member's root account id
-  accountId: String!
-
-  # Member's id
-  memberId: Int!
-
-  # The unique handle chosen by member
-  handle: String
-
-  # A Url to member's Avatar image
-  avatarUri: String
-
-  # Short text chosen by member to share information about themselves
-  about: String
-}
-```
-
-**Important** Relationship between types not supported yet!
-
-2. Block indexer is block consumer and every block can have events that we want to store their data. So indexing data from events we need to send the event to a function or a class that can handle the event and stores the event data on the database. `mappings` are the functions that we use to update our database with events data. Functions that we define in our mappings will be called only when the event name match our function name (function name pattern is `'handle' + eventName`). We call mapping functions as event handlers. Each event handler have only one parameter which is the `db: DB`. Every database operation is made with `db` object and the event can be accessed with `db` object. Below you can find an example for the event a handler:
-
-```ts
-// mappings/index.ts
-
-import { DB } from '../generated/indexer';
-
-export function handleMemberRegistered(db: DB) {
-  console.log(`Event parameters: ${db.event.event_params}`);
-}
-```
-
-3. Block indexer connects to a blockchain node via WebSocket so we need to tell block indexer where to find the address of the node. Also, on the initialization of the indexer, we must pass the type register function as a parameter. So we put these variables inside the `.env` file that indexer can find and use them. For Joystream we will be running a local development node and add the name of the function, the package for the type registration:
-
-```
-WS_PROVIDER_ENDPOINT_URI=ws://localhost:9944
-TYPE_REGISTER_PACKAGE_NAME=@joystream/types
-TYPE_REGISTER_FUNCTION=registerJoystreamTypes
-```
-
-4. Database connections options are defined in `.env`:
-
-```
-DB_NAME=test
-DB_USER=postgres
-DB_PASS=postgres
-DB_HOST=localhost
-DB_PORT=5432
-GRAPHQL_SERVER_PORT=4000
-```

+ 0 - 1
query-node/joystream-query-node/mappings/index.ts

@@ -1 +0,0 @@
-export * from './members';

+ 0 - 82
query-node/joystream-query-node/mappings/members.ts

@@ -1,82 +0,0 @@
-import * as assert from 'assert';
-import { CheckedUserInfo } from '@joystream/types/lib/members';
-
-import { Member } from '../generated/graphql-server/src/modules/member/member.model';
-import { DB, SubstrateEvent } from '../generated/indexer';
-
-export async function handleMemberRegistered(db: DB, event: SubstrateEvent) {
-  const { AccountId, MemberId } = event.event_params;
-
-  // Not safe type casting!
-  const userInfo = (event.extrinsic?.args[1].toJSON() as unknown) as CheckedUserInfo;
-
-  let member = new Member();
-  member.registeredAtBlock = event.block_number.toString();
-  member.memberId = MemberId.toString();
-  member.rootAccount = Buffer.from(AccountId);
-  member.controllerAccount = Buffer.from(AccountId);
-  member.handle = userInfo.handle.toString();
-  member.avatarUri = userInfo.avatar_uri.toString();
-  member.about = userInfo.about.toString();
-
-  db.save<Member>(member);
-}
-
-export async function handleMemberUpdatedAboutText(db: DB, event: SubstrateEvent) {
-  const { MemberId } = event.event_params;
-  const member = await db.get(Member, { where: { memberId: MemberId.toString() } });
-
-  assert(member);
-
-  // Not safe type casting!
-  const userInfo = (event.extrinsic?.args[1].toJSON() as unknown) as CheckedUserInfo;
-  member.about = userInfo.about.toString();
-
-  db.save<Member>(member);
-}
-
-export async function handleMemberUpdatedAvatar(db: DB, event: SubstrateEvent) {
-  const { MemberId } = event.event_params;
-  const member = await db.get(Member, { where: { memberId: MemberId.toString() } });
-
-  assert(member);
-
-  // Not safe type casting!
-  const userInfo = (event.extrinsic?.args[1].toJSON() as unknown) as CheckedUserInfo;
-  member.avatarUri = userInfo.avatar_uri.toString();
-
-  db.save<Member>(member);
-}
-
-export async function handleMemberUpdatedHandle(db: DB, event: SubstrateEvent) {
-  const { MemberId } = event.event_params;
-  const member = await db.get(Member, { where: { memberId: MemberId.toString() } });
-
-  assert(member);
-
-  // Not safe type casting!
-  const userInfo = (event.extrinsic?.args[1].toJSON() as unknown) as CheckedUserInfo;
-  member.handle = userInfo.handle.toString();
-
-  db.save<Member>(member);
-}
-
-export async function handleMemberSetRootAccount(db: DB, event: SubstrateEvent) {
-  const { MemberId, AccountId } = event.event_params;
-  const member = await db.get(Member, { where: { memberId: MemberId.toString() } });
-
-  assert(member);
-
-  member.rootAccount = Buffer.from(AccountId);
-  db.save<Member>(member);
-}
-
-export async function handleMemberSetControllerAccount(db: DB, event: SubstrateEvent) {
-  const { MemberId, AccountId } = event.event_params;
-  const member = await db.get(Member, { where: { memberId: MemberId.toString() } });
-
-  assert(member);
-
-  member.controllerAccount = Buffer.from(AccountId);
-  db.save<Member>(member);
-}

+ 0 - 21
query-node/joystream-query-node/schema.graphql

@@ -1,21 +0,0 @@
-type Member @entity {
-  memberId: BigInt!
-
-  # The unique handle chosen by member
-  handle: String @fulltext(query: "handles")
-
-  # A Url to member's Avatar image
-  avatarUri: String
-
-  # Short text chosen by member to share information about themselves
-  about: String
-
-  # Blocknumber when member was registered
-  registeredAtBlock: BigInt!
-
-  # Member's controller account id.
-  controllerAccount: Bytes!
-
-  # Member's root account id
-  rootAccount: Bytes!
-}

+ 0 - 14
query-node/joystream-query-node/scripts/reset-dev.sh

@@ -1,14 +0,0 @@
-#!/bin/sh
-set -x
-## restart postgres
-docker container ps | grep postgres | awk {'print $1'} | xargs -I {} docker restart {}
-## drop and create db
-cd ./../generated/graphql-server && yarn config:dev && yarn db:drop
-## wipe out indexer and graphql-server
-cd ./../../ && rm -rf ./generated/indexer && rm -rf ./generated/graphql-server
-## create both
-cli codegen
-## fire up and bootstrap the indexer
-cd ./generated/indexer && yarn start:dev &
-## start the graphql server
-cd ./../graphql-server && yarn start:dev &

+ 0 - 7
query-node/joystream-query-node/scripts/run-dev.sh

@@ -1,7 +0,0 @@
-#!/bin/sh
-## create both
-cd ./../ && cli codegen
-## fire up and bootstrap the indexer
-cd ./generated/indexer && yarn start:dev &
-## start the graphql server
-cd ./generated/graphql-server && yarn start:dev &

+ 0 - 16
query-node/substrate-query-framework/README.md

@@ -1,16 +0,0 @@
-# Substrate Query Node
-
-This repository is a package that you can use to build a query node. It contains source code Block Indexer and CLI tool.
-
-## Data Store
-
-Block indexer store event data into a postgresql database. You can run the database with docker.
-
-```text
-$ docker-compose up -d
-```
-
-## CLI Tool
-
-CLI generates a GraphQL Server and a Block Indexer for Substrate based chains. How to use CLI [CLI](cli/)
-

+ 0 - 2
query-node/substrate-query-framework/cli/.eslintignore

@@ -1,2 +0,0 @@
-/lib
-/src/templates/

+ 0 - 15
query-node/substrate-query-framework/cli/.eslintrc.js

@@ -1,15 +0,0 @@
-module.exports = {
-    extends: [
-		"eslint:recommended",
-		"plugin:@typescript-eslint/eslint-recommended",
-		"plugin:@typescript-eslint/recommended",
-		"plugin:@typescript-eslint/recommended-requiring-type-checking"
-	],
-	parser: "@typescript-eslint/parser",
-	parserOptions: {
-        project: './tsconfig.json',
-        tsconfigRootDir: __dirname,
-        //debugLevel: true
-	},
-	plugins: ["@typescript-eslint"]
-}

+ 0 - 9
query-node/substrate-query-framework/cli/.gitignore

@@ -1,9 +0,0 @@
-*-debug.log
-*-error.log
-/.nyc_output
-/dist
-/lib
-/package-lock.json
-/tmp
-node_modules
-.editorconfig

+ 0 - 10
query-node/substrate-query-framework/cli/.prettierrc.js

@@ -1,10 +0,0 @@
-// prettier.config.js or .prettierrc.js
-module.exports = {
-  trailingComma: "es5",
-  tabWidth: 2,
-  semi: true,
-  singleQuote: true,
-  arrowParens: "avoid",
-  printWidth: 120,
-  useTabs: false
-};

+ 0 - 143
query-node/substrate-query-framework/cli/README.md

@@ -1,143 +0,0 @@
-# Hydra CLI
-
-A query node for substrate based chains, inspired by TheGraph.
-
-USAGE
-
-```bash
-$ hydra-cli [COMMAND]
-```
-
-COMMANDS
-
-```bash
-scaffold  Generate a starter project with a sample schema file and mappings
-codegen   Generate a ready to run graphql server and block indexer
-preview   Preview the output schema served by the GraphQL server
-```
-
-## Using Hydra CLI
-
-Using `npx`:
-
-```bash
-$ alias hydra-cli='npx @dzlzv/hydra-cli'
-```
-
-or install via npm:
-
-```bash
-npm install -g @dzlzv/hydra-cli
-```
-and then
-
-```bash
-$ hydra-cli [COMMAND]
-```
-
-## Getting Started
-
-Run
-
-```
-$ hydra-cli scaffold
-```
-and answer the prompts. The scaffolder will generate the following files:
-
-```text
-├── .env
-├── docker-compose.yml
-├── docker
-├── mappings
-├── package.json
-└── schema.graphql
-```
-
-By defualt the scaffolder generates mappings and a schema describing Kusama Treasury proposals.
-Generate the indexer and the server:
-
-```bash
-$ hydra-cli codegen
-```
-
-The indexer and server files will be generated in `./generated/indexer` and `./generated/graphql-server` respectively.
-
-In order to run them, a Postges database should be up and running and accept connections. The credentials should be provided in `.env` file. By default, the scaffolder generates a database service  `docker-compose.yml` with the credentials provided. Run 
-
-```bash
-$ yarn db:start
-$ yarn db:bootstrap
-```
-
-to create the database and set up the schema (if the database already exists, skip the first one).
-
-Now spin up the server and the indexer:
-
-```bash
-$ yarn indexer:start
-```
-
-```bash
-$ yarn server:start:dev
-```
-
-### Generate Graphql Server and Block Indexer
-
-Hydra Cli creates a folder named `generated` and puts everthing inside it.
-
-```bash
-$ hydra-cli codegen
-```
-
-Make sure `package.json` is in you cwd. Start graphql server with a GraphQL playground:
-
-```bash
-$ yarn server:start:dev
-```
-
-Start block indexer:
-
-```bash
-$ yarn indexer:start
-```
-
-## Prerequisites
-
-Hydra CLI generates a grapqh server and a substrate block indexer.
-
-- Graphql server uses warthog underneath. Hydra generates `model/resolver/service` from the schema that you define in the current working directory (cwd) in a file named `schema.graphql`. For a guide on how to write a schema, follow the [docs](https://app.gitbook.com/@dzhelezov/s/hydra-docs/v/query_node_spec/query-node/docs).
-  
-- Block indexer consumes produced blocks from a substrate based chain. Before running code generation make sure you have `.env` file inside the cwd, and `mappings` directory with `index.ts`. All mapping functions should be exported
-  
-- Which must have variables below with appropriate values:
-
-```
-# Project name
-PROJECT_NAME=test
-
-# Substrate endpoint to source events from
-WS_PROVIDER_ENDPOINT_URI=
-# block height to start the indexer from
-BLOCK_HEIGHT=0
-
-# DB config to create a database (use db tools only for development!)
-DB_NAME=test
-DB_USER=postgres
-DB_PASS=postgres
-DB_HOST=localhost
-DB_PORT=5432
-
-# GraphQL server HOST and PORT
-GRAPHQL_SERVER_PORT=4000
-GRAPHQL_SERVER_HOST=localhost
-WARTHOG_APP_PORT=4000
-WARTHOG_APP_HOST=localhost
-
-WS_PROVIDER_ENDPOINT_URI=<provider>    # e.g ws://localhost:9944
-TYPE_REGISTER_PACKAGE_NAME=<packname>  # name of the package to import TYPE_REGISTER_FUNCTION
-TYPE_REGISTER_FUNCTION=<register_type> # name of the function that will called for type registration
-```
-
-## Examples
-
-Check out [sample projects](https://github.com/Joystream/joystream/tree/query_node/query-node/examples) for inspiration!

+ 0 - 2
query-node/substrate-query-framework/cli/bin/README.md

@@ -1,2 +0,0 @@
-# bin
-

+ 0 - 5
query-node/substrate-query-framework/cli/bin/run

@@ -1,5 +0,0 @@
-#!/usr/bin/env node
-
-require('@oclif/command').run()
-.then(require('@oclif/command/flush'))
-.catch(require('@oclif/errors/handle'))

+ 0 - 3
query-node/substrate-query-framework/cli/bin/run.cmd

@@ -1,3 +0,0 @@
-@echo off
-
-node "%~dp0\run" %*

+ 0 - 6
query-node/substrate-query-framework/cli/bin/run.md

@@ -1,6 +0,0 @@
-# run
-
-@echo off
-
-node "%~dp0\run" %\*
-

+ 0 - 101
query-node/substrate-query-framework/cli/package.json

@@ -1,101 +0,0 @@
-{
-  "name": "@dzlzv/hydra-cli",
-  "description": "CLI tool for building a Hydra query node",
-  "version": "0.0.12",
-  "author": "metmirr @metmirr dzlzv @dzhelezov",
-  "bin": {
-    "hydra-cli": "./bin/run"
-  },
-  "bugs": "https://github.com/joystream/joystream/joystream-query-node/cli/issues",
-  "dependencies": {
-    "@oclif/command": "^1.5.20",
-    "@oclif/config": "^1",
-    "@oclif/errors": "^1.3.3",
-    "@oclif/plugin-help": "^2",
-    "@types/fs-extra": "^8.1.0",
-    "@types/graphql": "^14.5.0",
-    "@types/listr": "^0.14.2",
-    "@types/mustache": "^4.0.1",
-    "@types/node": "^12.12.30",
-    "cli-ux": "^5.4.9",
-    "execa": "^4.0.3",
-    "fs-extra": "^9.0.0",
-    "gluegun": "^4.3.1",
-    "graphql": "^15.0.0",
-    "listr": "^0.14.3",
-    "lodash": "^4.17.15",
-    "mustache": "^4.0.1",
-    "tslib": "1.11.2",
-    "typeorm-model-generator": "^0.4.2",
-    "warthog": "https://github.com/metmirr/warthog/releases/download/v2.9.7/warthog-v2.9.7.tgz"
-  },
-  "devDependencies": {
-    "@oclif/dev-cli": "^1",
-    "@oclif/test": "^1",
-    "@types/chai": "^4",
-    "@types/mocha": "^7.0.2",
-    "@types/temp": "^0.8.34",
-    "@types/tmp": "^0.2.0",
-    "@typescript-eslint/eslint-plugin": "^3.0.2",
-    "@typescript-eslint/parser": "^3.0.2",
-    "chai": "^4",
-    "eslint": "^7.1.0",
-    "globby": "^10",
-    "husky": "^4.2.5",
-    "jest": "^26.0.1",
-    "lint-staged": "^10.2.6",
-    "mocha": "^5",
-    "mocha-chai-snapshot": "^1.0.0",
-    "nyc": "^14",
-    "prettier": "^2.0.5",
-    "spawn-command": "^0.0.2-1",
-    "temp": "^0.9.1",
-    "ts-node": "^8",
-    "typescript": "^3.9.3"
-  },
-  "engines": {
-    "node": ">=8.0.0"
-  },
-  "files": [
-    "/bin",
-    "/lib",
-    "/npm-shrinkwrap.json",
-    "/oclif.manifest.json"
-  ],
-  "homepage": "https://github.com/joystream/joystream/query-node/substrate-query-framework/cli",
-  "keywords": [
-    "oclif"
-  ],
-  "license": "MIT",
-  "main": "lib/index.js",
-  "oclif": {
-    "commands": "./lib/src/commands",
-    "bin": "hydra-cli",
-    "plugins": [
-      "@oclif/plugin-help",
-      "@oclif/errors"
-    ]
-  },
-  "repository": "git@github.com:Joystream/joystream.git",
-  "scripts": {
-    "build": "rm -rf lib && tsc --build tsconfig.json",
-    "postpack": "rm -f oclif.manifest.json",
-    "lint": "eslint . --cache --ext .ts --config .eslintrc.js",
-    "prepack": "rm -rf lib && tsc -b && cp -R ./src/templates ./lib/src/templates && oclif-dev manifest && oclif-dev readme",
-    "test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\"",
-    "version": "oclif-dev readme && git add README.md"
-  },
-  "types": "lib/index.d.ts",
-  "resolutions": {
-    "tslib": "1.11.2"
-  },
-  "husky": {
-    "hooks": {
-      "pre-commit": "lint-staged",
-      "pre-push": "yarn test"
-    }
-  },
-  "lint-staged": {
-    "*.ts": "yarn lint"
-  }
-}

+ 0 - 130
query-node/substrate-query-framework/cli/src/commands/codegen.ts

@@ -1,130 +0,0 @@
-import * as path from 'path';
-import * as fs from 'fs-extra';
-import * as dotenv from 'dotenv';
-import * as Mustache from 'mustache';
-import { readFileSync } from 'fs-extra';
-import { Command, flags } from '@oclif/command';
-
-import cli from 'cli-ux';
-import execa = require('execa');
-
-import { createDir, getTemplatePath, createFile } from '../utils/utils';
-import { formatWithPrettier } from '../helpers/formatter';
-import WarthogWrapper from '../helpers/WarthogWrapper';
-import { getTypeormConfig } from '../helpers/db';
-import { upperFirst } from 'lodash';
-import Listr = require('listr');
-
-export default class Codegen extends Command {
-  static description = 'Code generator';
-  static generatedFolderName = 'generated';
-
-  static flags = {
-    schema: flags.string({ char: 's', description: 'Schema path', default: '../../schema.graphql' }),
-    // pass --no-indexer to skip indexer generation
-    indexer: flags.boolean({ char: 'i', allowNo: true, description: 'Generate Indexer', default: true }),
-    // pass --no-graphql to skip graphql generation
-    graphql: flags.boolean({ char: 'g', allowNo: true, description: 'Generate GraphQL server', default: true }),
-
-    dbschema: flags.boolean({ char: 'd', description: 'Create the DB schema (use with caution!)', default: false }),
-  };
-
-  async run(): Promise<void> {
-    dotenv.config();
-
-    const { flags } = this.parse(Codegen);
-
-    const generatedFolderPath = path.resolve(process.cwd(), Codegen.generatedFolderName);
-
-    createDir(generatedFolderPath);
-
-    // Change directory to generated
-    process.chdir(generatedFolderPath);
-
-    // Create warthog graphql server
-    if (flags.graphql) {
-      cli.action.start('Generating the GraphQL server');
-      await this.createGraphQLServer(flags.schema, flags.dbschema);
-      cli.action.stop();
-    }
-
-    // Create block indexer
-    if (flags.indexer) {
-      cli.action.start('Generating the Indexer');
-      await this.createBlockIndexer();
-      cli.action.stop();
-    }
-  }
-
-  async createGraphQLServer(schemaPath: string, syncdb: boolean): Promise<void> {
-    const goBackDir = process.cwd();
-
-    const warthogProjectName = 'graphql-server';
-    const warthogProjectPath = path.resolve(goBackDir, warthogProjectName);
-
-    createDir(warthogProjectPath);
-
-    process.chdir(warthogProjectPath);
-
-    const warthogWrapper = new WarthogWrapper(this, schemaPath);
-    await warthogWrapper.run();
-
-    if (syncdb) {
-      await warthogWrapper.generateDB();
-    }
-
-    process.chdir(goBackDir);
-  }
-
-  async createBlockIndexer(): Promise<void> {
-    // Take process where back at the end of the function execution
-    const goBackDir = process.cwd();
-
-    // Block indexer folder path
-    const indexerPath = path.resolve(goBackDir, 'indexer');
-
-    createDir(indexerPath);
-    process.chdir(indexerPath);
-
-    const generateFiles = {
-      title: 'Generate source files',
-      task: async () => {
-        let indexFileContent = readFileSync(getTemplatePath('index-builder-entry.mst'), 'utf8');
-        indexFileContent = Mustache.render(indexFileContent, {
-          packageName: process.env.TYPE_REGISTER_PACKAGE_NAME,
-          typeRegistrator: process.env.TYPE_REGISTER_FUNCTION,
-          projectName: upperFirst(process.env.PROJECT_NAME),
-        });
-        createFile(path.resolve('index.ts'), formatWithPrettier(indexFileContent));
-
-        // Create package.json
-        await fs.copyFile(getTemplatePath('indexer.package.json'), path.resolve(process.cwd(), 'package.json'));
-
-        // Create .env file for typeorm database connection
-        await fs.writeFile('.env', getTypeormConfig());
-
-        // Create
-        await fs.copyFile(getTemplatePath('indexer.tsconfig.json'), path.resolve(process.cwd(), 'tsconfig.json'));
-      },
-    };
-    // Create index.ts file
-
-    const installDeps = {
-      title: 'Install dependencies for the Indexer',
-      task: async () => {
-        await execa('yarn', ['install']);
-        if (process.env.TYPE_REGISTER_PACKAGE_NAME) {
-          const lib = process.env.TYPE_REGISTER_PACKAGE_VERSION
-            ? `${process.env.TYPE_REGISTER_PACKAGE_NAME}@${process.env.TYPE_REGISTER_PACKAGE_VERSION}`
-            : `${process.env.TYPE_REGISTER_PACKAGE_NAME}`;
-          await execa('yarn', ['add', `${lib}`]);
-        }
-      },
-    };
-
-    const listr = new Listr([generateFiles, installDeps]);
-    await listr.run();
-
-    process.chdir(goBackDir);
-  }
-}

+ 0 - 21
query-node/substrate-query-framework/cli/src/commands/db.ts

@@ -1,21 +0,0 @@
-import { Command, flags } from '@oclif/command';
-
-import { resetLastProcessedEvent } from '../helpers/db';
-
-export default class DB extends Command {
-  static description = 'Typeorm commands';
-
-  static flags = {
-    reset: flags.boolean({ char: 'r', default: true, description: 'Reset last processed event to genesis' }),
-  };
-
-  async run(): Promise<void> {
-    const { flags } = this.parse(DB);
-
-    if (flags.reset) {
-      this.log('Resetting the last processed event...');
-      await resetLastProcessedEvent();
-      this.log('Done...');
-    }
-  }
-}

+ 0 - 49
query-node/substrate-query-framework/cli/src/commands/preview.ts

@@ -1,49 +0,0 @@
-import { Command, flags } from '@oclif/command';
-import { createDir } from '../utils/utils';
-import * as path from 'path';
-import * as fs from 'fs-extra';
-import Codegen from './codegen';
-import WarthogWrapper from '../helpers/WarthogWrapper';
-import * as dotenv from 'dotenv';
-
-export default class Preview extends Command {
-  static description = 'Preview GraphQL API schema';
-
-  static flags = {
-    schema: flags.string({ char: 's', description: 'Schema path', default: '../../schema.graphql' }),
-  };
-
-  async run(): Promise<void> {
-    const { flags } = this.parse(Codegen);
-    dotenv.config();
-
-    const generatedFolderPath = path.resolve(process.cwd(), Codegen.generatedFolderName);
-    const isGeneratedFolderPathExists = fs.existsSync(generatedFolderPath);
-
-    createDir(generatedFolderPath);
-
-    // Change directory to generated
-    process.chdir(generatedFolderPath);
-    await this.generateAPIPreview(flags.schema, generatedFolderPath, isGeneratedFolderPathExists);
-  }
-
-  async generateAPIPreview(schemaPath: string, generatedFolderPath: string, isExists: boolean): Promise<void> {
-    const warthogProjectPath = path.resolve(process.cwd(), 'api-preview');
-
-    createDir(warthogProjectPath);
-    process.chdir(warthogProjectPath);
-
-    await new WarthogWrapper(this, schemaPath).run();
-
-    fs.copyFileSync(
-      path.resolve(warthogProjectPath, Codegen.generatedFolderName, 'schema.graphql'),
-      path.resolve('../../apipreview.graphql')
-    );
-    // if 'generated' folder was already there dont delete it otherwise delete
-    if (!isExists) {
-      this.log('Removing unused files...');
-      fs.removeSync(generatedFolderPath);
-      this.log('Generated API Preview file -> apipreview.graphql');
-    }
-  }
-}

+ 0 - 143
query-node/substrate-query-framework/cli/src/commands/scaffold.ts

@@ -1,143 +0,0 @@
-import { Command, flags } from '@oclif/command';
-import * as fs from 'fs-extra';
-import * as path from 'path';
-import * as utils from './../utils/utils';
-import cli from 'cli-ux';
-import { getTemplatePath } from '../utils/utils';
-import Mustache = require('mustache');
-import dotenv = require('dotenv');
-import execa = require('execa');
-
-const DEFAULT_WS_API_ENDPOINT = 'wss://kusama-rpc.polkadot.io/';
-
-export default class Scaffold extends Command {
-  static description = `Starter kit: generates a directory layout and a sample schema file`;
-
-  static flags = {
-    projectName: flags.string({ char: 'n', description: 'Project name' }),
-    wsProviderUrl: flags.string({
-      char: 'n',
-      description: 'Substrate WS provider endpoint',
-      default: DEFAULT_WS_API_ENDPOINT,
-    }),
-    blockHeight: flags.string({ char: 'b', description: 'Start block height', default: '0' }),
-    dbHost: flags.string({ char: 'h', description: 'Database host', default: 'localhost' }),
-    dbPort: flags.string({ char: 'p', description: 'Database port', default: '5432' }),
-    dbUser: flags.string({ char: 'u', description: 'Database user', default: 'postgres' }),
-    dbPassword: flags.string({ char: 'x', description: 'Database user password', default: 'postgres' }),
-    appPort: flags.string({ char: 'a', description: 'GraphQL server port', default: '4000' }),
-  };
-
-  async run(): Promise<void> {
-    const { flags } = this.parse(Scaffold);
-
-    await fs.writeFile(
-      path.join(process.cwd(), '.env'),
-      flags.projectName ? await this.dotenvFromFlags(flags) : await this.promptDotEnv()
-    );
-
-    dotenv.config();
-
-    this.log('Your settings have been saved to .env, feel free to edit');
-
-    cli.action.start('Scaffolding');
-
-    // TODO: we don't do bootstrapping for now
-    //await fs.ensureDir('bootstrap');
-    // copy sample graphql schema
-    await utils.copyTemplateToCWD('scaffold/schema.graphql', 'schema.graphql');
-
-    await this.setupMappings();
-    await this.setupNodeProject();
-    await this.setupDocker();
-
-    cli.action.stop();
-  }
-
-  async dotenvFromFlags(flags_: { [key: string]: string | undefined }): Promise<string> {
-    const template = await fs.readFile(getTemplatePath('scaffold/.env'), 'utf-8');
-    return Mustache.render(template, { ...flags_, dbName: flags_.projectName });
-  }
-
-  async promptDotEnv(): Promise<string> {
-    let ctx: Record<string, string> = {};
-
-    const projectName = (await cli.prompt('Enter your project name', { required: true })) as string;
-    ctx = { ...ctx, projectName };
-
-    const wsProviderUrl = (await cli.prompt('Substrate WS provider endpoint', {
-      default: DEFAULT_WS_API_ENDPOINT,
-    })) as string;
-
-    ctx = { ...ctx, wsProviderUrl };
-    
-    ctx = await this.promptCustomTypes(ctx);
-
-    const blockHeight = (await cli.prompt('Start block height', { default: '0' })) as string;
-    ctx = { ...ctx, blockHeight };
-
-    if (isNaN(parseInt(blockHeight))) {
-      throw new Error('Starting block height must be an integer');
-    }
-
-    const dbName = (await cli.prompt('Database name', { default: projectName })) as string;
-    ctx = { ...ctx, dbName };
-    const dbHost = (await cli.prompt('Database host', { default: 'localhost' })) as string;
-    ctx = { ...ctx, dbHost };
-    const dbPort = (await cli.prompt('Database port', { default: '5432' })) as string;
-    ctx = { ...ctx, dbPort };
-    const dbUser = (await cli.prompt('Database user', { default: 'postgres' })) as string;
-    ctx = { ...ctx, dbUser };
-    const dbPassword = (await cli.prompt('Database user password', { type: 'mask', default: 'postgres' })) as string;
-    ctx = { ...ctx, dbPassword };
-    const appPort = (await cli.prompt('GraphQL server port', { default: '4000' })) as string;
-    ctx = { ...ctx, appPort };
-    const template = await fs.readFile(getTemplatePath('scaffold/.env'), 'utf-8');
-
-    return Mustache.render(template, ctx);
-  }
-
-  async promptCustomTypes(ctx: Record<string, string>): Promise<Record<string, string>> {
-    const proceed = await cli.confirm('Do you have a custom type library?')
-    if (!proceed) {
-      return ctx;
-    }
-    const typeLib = (await cli.prompt('Please provide type library', { default: '@polkadot/types' })) as string;
-    let _ctx: Record<string, string> = { ...ctx, typeLib };
-    const typeVer = (await cli.prompt('Please provide library version')) as string;
-    _ctx = { ..._ctx, typeVer };
-    const typeFun = (await cli.prompt('What is the function name for type registration ')) as string;
-    _ctx = { ..._ctx, typeFun };
-    return _ctx;
-  }
-
-  // For now, we simply copy the hardcoded templates
-  async setupMappings(): Promise<void> {
-    await fs.ensureDir('mappings');
-    await utils.copyTemplateToCWD('scaffold/mappings/index.ts', path.join('mappings', 'index.ts'));
-    await utils.copyTemplateToCWD('scaffold/mappings/proposal.ts', path.join('mappings', 'proposal.ts'));
-  }
-
-  async setupDocker(): Promise<void> {
-    await fs.ensureDir('docker');
-    await utils.copyTemplateToCWD('scaffold/docker-compose.yml', 'docker-compose.yml');
-
-    await utils.copyTemplateToCWD('scaffold/docker/Dockerfile.indexer', path.join('docker', 'Dockerfile.indexer'));
-    await utils.copyTemplateToCWD('scaffold/docker/Dockerfile.server', path.join('docker', 'Dockerfile.server'));
-
-    await utils.copyTemplateToCWD('scaffold/.dockerignore', '.dockerignore');
-  }
-
-  async setupNodeProject(): Promise<void> {
-    const template = await fs.readFile(getTemplatePath('scaffold/package.json'), 'utf-8');
-
-    await fs.writeFile(
-      path.join(process.cwd(), 'package.json'),
-      Mustache.render(template, {
-        projectName: process.env.PROJECT_NAME,
-      })
-    );
-
-    await execa('yarn', ['install']);
-  }
-}

+ 0 - 31
query-node/substrate-query-framework/cli/src/generate/AbstractRenderer.ts

@@ -1,31 +0,0 @@
-import { GeneratorContext } from './SourcesGenerator';
-import { WarthogModel } from '../model';
-import Mustache from 'mustache';
-import Debug from 'debug';
-import * as prettier from 'prettier';
-
-const debug = Debug('qnode-cli:abstract-renderer');
-
-export abstract class AbstractRenderer {
-  protected context: GeneratorContext = {};
-  protected model: WarthogModel;
-
-  constructor(model: WarthogModel, context: GeneratorContext = {}) {
-    this.context = context;
-    this.model = model;
-  }
-
-  abstract transform(): GeneratorContext;
-
-  render(mustacheTeplate: string): string {
-    const mustacheContext = this.transform();
-    debug(`Rendering with context: ${JSON.stringify(mustacheContext, null, 2)}`);
-
-    const rendered = Mustache.render(mustacheTeplate, mustacheContext);
-    return prettier.format(rendered, {
-      parser: 'typescript',
-      singleQuote: true,
-      printWidth: 120,
-    });
-  }
-}

+ 0 - 32
query-node/substrate-query-framework/cli/src/generate/ConfigProvider.ts

@@ -1,32 +0,0 @@
-import { Config } from 'warthog';
-import * as path from 'path';
-import * as util from './utils';
-import { GeneratorContext } from './SourcesGenerator';
-
-export class ConfigProvider {
-  readonly config: Config;
-  readonly cliGeneratedPath: string;
-
-  constructor() {
-    this.config = new Config();
-    this.config.loadSync();
-
-    this.cliGeneratedPath = path.join(this.config.get('ROOT_FOLDER'), '/', this.config.get('CLI_GENERATE_PATH'), '/');
-  }
-
-  withGeneratedFolderRelPath(name: string): GeneratorContext {
-    const destFolder = this.getDestFolder(name);
-    const generatedFolderRelPath = path.relative(destFolder, this.config.get('GENERATED_FOLDER'));
-    return {
-      generatedFolderRelPath,
-    };
-  }
-
-  getDestFolder(name: string): string {
-    return util.supplant(this.cliGeneratedPath, util.names(name));
-  }
-
-  getMigrationsFolder(): string {
-    return this.config.get('DB_MIGRATIONS_DIR') as string;
-  }
-}

+ 0 - 44
query-node/substrate-query-framework/cli/src/generate/EnumContextProvider.ts

@@ -1,44 +0,0 @@
-import { GeneratorContext } from './SourcesGenerator';
-import { withEnum } from './enum-context';
-import { GraphQLEnumType } from 'graphql';
-import Debug from 'debug';
-
-const debug = Debug('qnode-cli:enum-ctx-provider');
-
-export class EnumContextProvider {
-  readonly exported: { [key: string]: boolean } = {};
-
-  withEnum(enumType: GraphQLEnumType): GeneratorContext {
-    return {
-      ...this.withExport(enumType.name),
-      ...withEnum(enumType),
-    };
-  }
-
-  withExport(enumType: string): GeneratorContext {
-    if (!this.exported[enumType]) {
-      this.exported[enumType] = true;
-      return {
-        // wether the enum should be exported in the template. It must be done only once
-        export: true,
-      };
-    }
-    debug(`Enum ${enumType} is already exported`);
-    return {};
-  }
-
-  // withEnums(objType: ObjectType): GeneratorContext {
-  //   const referncedEnums = new Set<GraphQLEnumType>();
-  //   objType.fields.map(f => {
-  //     if (f.isEnum()) referncedEnums.add(this.model.lookupEnum(f.type));
-  //   });
-  //   const enums: GeneratorContext[] = [];
-  //   for (const e of referncedEnums) {
-  //     enums.push(this.withEnum(e));
-  //   }
-  //   debug(`With enums: ${JSON.stringify(enums, null, 2)}`);
-  //   return {
-  //     enums,
-  //   };
-  // }
-}

+ 0 - 16
query-node/substrate-query-framework/cli/src/generate/EnumRenderer.ts

@@ -1,16 +0,0 @@
-import { AbstractRenderer } from './AbstractRenderer';
-import { withEnum } from './enum-context';
-import { GeneratorContext } from './SourcesGenerator';
-
-export class EnumRenderer extends AbstractRenderer {
-  transform(): GeneratorContext {
-    const enums: GeneratorContext[] = [];
-    this.model.enums.map(e => {
-      enums.push(withEnum(e));
-    });
-    return {
-      enums,
-    };
-  }
-
-}

+ 0 - 153
query-node/substrate-query-framework/cli/src/generate/FTSQueryRenderer.ts

@@ -1,153 +0,0 @@
-import Mustache from 'mustache';
-import Debug from 'debug';
-import { FTSQuery, ObjectType } from '../model';
-import { upperFirst, lowerFirst, kebabCase } from 'lodash';
-import { snakeCase } from 'typeorm/util/StringUtils';
-import { GeneratorContext } from '../generate/SourcesGenerator';
-
-const debug = Debug('qnode-cli:model-generator');
-
-interface MustacheQuery {
-    entities: MustacheOrmEnitity[],
-    query: {
-        name: string,
-        typePrefix: string, // used to define types for inputs and outputs
-        viewName: string, // view name holding the union of the documents
-        language: string, 
-        documents: MustacheQueryDocument[], // all text fields in a table are grouped into documents
-        ts: number // migration timestamp
-    }
-}
-
-interface MustacheOrmEnitity {
-    type: string,
-    fieldName: string,
-    arrayName: string,
-    table: string, // SQL table the enitity is mapped to
-    model: string,  // warthog model name
-    last: boolean
-}
-
-interface MustacheQueryDocument {
-    tsvColumn: string, // generated column to be used for the ts_vector index
-    docColumn: string, // generated column where the concatenated fields as a doc are stored
-    index_name: string, // name of the ts_vector index
-    table: string, // SQL table the text fields belong to 
-    fields: MustacheQueryField[] // text fields to be grouped into a document
-    last: boolean // if its last in the list of documents
-}
-
-interface MustacheQueryField {
-    weight: string, // reserved; can be 'A', 'B', 'C' or 'D'. Always set to 'A' for now.
-    column: string,  // SQL column this field is mapped to
-    last: boolean // this field is need for joining, e.g. '<field> || <field> || <field>'
-}
-
-
-
-export class FTSQueryRenderer {
-    private _context: GeneratorContext = {};
-
-    constructor(context: GeneratorContext = {}) {
-        this._context = context;
-    }
-    
-    generate(mustacheTeplate: string, query: FTSQuery):string {
-        debug(`Generating query with ${JSON.stringify(query, null, 2)}`);
-        const mustacheQuery = this.transform(query);
-        return Mustache.render(mustacheTeplate, mustacheQuery);
-    }
-
-    private transform(query: FTSQuery): MustacheQuery {
-        if (query.clauses.length == 0) {
-            throw new Error("A query should contain at least one clause");
-        }
-
-        const prefix = this.queryName2prefix(query.name);
-
-        //const entityObjType = this.lookupType(query.fields[0]);
-        const entities: MustacheOrmEnitity[] = [];
-        const documents: MustacheQueryDocument[] = [];
-        
-        const name2doc: { [entity:string]: MustacheQueryDocument } = {};
-        const name2entity: { [entity:string]: MustacheOrmEnitity } = {};
-
-        query.clauses.map((v) => {
-            if (!name2doc[v.entity.name]) {
-                const table = this.name2table(v.entity.name);
-                name2doc[v.entity.name] = {
-                    tsvColumn: `${prefix}_tsv`,
-                    docColumn: `${prefix}_doc`,
-                    index_name: `${prefix}_${table}_idx`,
-                    table,
-                    fields: [],
-                    last: false
-                };
-                name2entity[v.entity.name] = this.objectTypeToMustache(v.entity);
-            }
-            name2doc[v.entity.name].fields.push({
-                column: this.name2column(v.field.name),
-                weight: 'A',
-                last: false
-            });
-            
-        })
-
-        Object.entries(name2doc).forEach(([entityName, doc]) => {
-            entities.push(name2entity[entityName]);
-            doc.fields[doc.fields.length - 1].last = true;
-            documents.push(doc);
-        })
-        
-        documents[documents.length - 1].last = true;
-        entities[entities.length - 1].last = true;
-        
-        return {
-            entities,
-            query: {
-                viewName: `${prefix}_view`,
-                typePrefix: upperFirst(query.name),
-                name: query.name,
-                language: 'english',// only English is supported for now
-                documents,
-                ts: (this._context["ts"]) ? this._context["ts"] as number : Date.now()
-            }
-        }
-    }
-
-    private objectTypeToMustache(objType: ObjectType): MustacheOrmEnitity {
-        return {
-            type: upperFirst(objType.name),
-            table: this.name2table(objType.name), 
-            model: this.name2modelName(objType.name),
-            fieldName: this.fieldName(objType.name),
-            arrayName: this.arrayName(objType.name),
-            last: false
-        }
-    } 
-
-    // TODO: hmm this really depends on typeorm naming strategy
-    private name2column(name: string):string {
-        return `"${name}"`;
-    }
-
-    private name2table(name: string): string {
-        return snakeCase(name);
-    }
-
-    private queryName2prefix(qName: string): string {
-        return snakeCase(qName);
-    }
-
-    private name2modelName(name: string): string {
-        return kebabCase(name);
-    }
-
-    private fieldName(name: string): string {
-        return lowerFirst(name);
-    }
-
-    private arrayName(name: string): string {
-        return `${this.fieldName(name)}s`;
-    }
-}

+ 0 - 167
query-node/substrate-query-framework/cli/src/generate/ModelRenderer.ts

@@ -1,167 +0,0 @@
-import * as path from 'path';
-import { ObjectType, WarthogModel, FieldResolver } from '../model';
-import Debug from 'debug';
-import { GeneratorContext } from './SourcesGenerator';
-import { buildFieldContext } from './field-context';
-import * as utils from './utils';
-import { GraphQLEnumType } from 'graphql';
-import { AbstractRenderer } from './AbstractRenderer';
-import { EnumContextProvider } from './EnumContextProvider';
-
-const debug = Debug('qnode-cli:model-renderer');
-
-export class ModelRenderer extends AbstractRenderer {
-  private objType: ObjectType;
-  private enumCtxProvider: EnumContextProvider;
-
-  constructor(
-    model: WarthogModel,
-    objType: ObjectType,
-    enumContextProvider: EnumContextProvider,
-    context: GeneratorContext = {}
-  ) {
-    super(model, context);
-    this.objType = objType;
-    this.enumCtxProvider = enumContextProvider;
-  }
-
-  withInterfaceProp(): GeneratorContext {
-    return {
-      isInterface: this.objType.isInterface,
-    };
-  }
-
-  withInterfaces(): GeneratorContext {
-    if (utils.hasInterfaces(this.objType) && this.objType.interfaces !== undefined) {
-      return {
-        interfaces: [utils.withNames(this.objType.interfaces[0].name)],
-      };
-    }
-    return {};
-  }
-
-  withSubclasses(): GeneratorContext {
-    if (this.objType.isInterface !== true) {
-      return {};
-    }
-    const subclasses: GeneratorContext[] = [];
-    this.model.getSubclasses(this.objType.name).map(o => subclasses.push(utils.withNames(o.name)));
-    return {
-      subclasses,
-    };
-  }
-
-  withEnums(): GeneratorContext {
-    // we need to have a state to render exports only once
-    const referncedEnums = new Set<GraphQLEnumType>();
-    this.objType.fields.map(f => {
-      if (f.isEnum()) referncedEnums.add(this.model.lookupEnum(f.type));
-    });
-    const enums: GeneratorContext[] = [];
-    for (const e of referncedEnums) {
-      enums.push(this.enumCtxProvider.withEnum(e));
-    }
-    return {
-      enums,
-    };
-  }
-
-  withFields(): GeneratorContext {
-    const fields: GeneratorContext[] = [];
-
-    utils.ownFields(this.objType).map(f => fields.push(buildFieldContext(f, this.objType)));
-    return {
-      fields,
-    };
-  }
-
-  withDescription(): GeneratorContext {
-    return {
-      description: this.objType.description || undefined,
-    };
-  }
-
-  withHasProps(): GeneratorContext {
-    const has: GeneratorContext = {};
-    for (const field of this.objType.fields) {
-      let ct = field.columnType();
-      if (ct === 'numeric' || ct === 'decimal') ct = 'numeric';
-      has[ct] = true;
-    }
-    has['array'] = this.objType.fields.some(f => f.isArray());
-    has['enum'] = this.objType.fields.some(f => f.isEnum());
-    has['union'] = this.objType.fields.some(f => f.isUnion());
-
-    debug(`ObjectType has: ${JSON.stringify(has, null, 2)}`);
-
-    return {
-      has,
-    };
-  }
-
-  withImportProps(): GeneratorContext {
-    const relatedEntityImports: Set<string> = new Set();
-
-    this.objType.fields
-      .filter(f => f.relation)
-      .forEach(f => {
-        const columnType = f.relation?.columnType;
-        if (!columnType) {
-          // should never happen
-          throw new Error(`Relation column type for ${f.name} is undefined`);
-        }
-        relatedEntityImports.add(
-          path.join(
-            `import { ${columnType} } from  '..`,
-            utils.kebabCase(columnType),
-            `${utils.kebabCase(columnType)}.model'`
-          )
-        );
-      });
-    return {
-      relatedEntityImports: Array.from(relatedEntityImports.values()),
-    };
-  }
-
-  withFieldResolvers(): GeneratorContext {
-    const fieldResolvers: FieldResolver[] = [];
-    const fieldResolverImports: Set<string> = new Set();
-    const entityName = this.objType.name;
-
-    for (const f of this.objType.fields) {
-      if (!f.relation) continue;
-      const returnTypeFunc = f.relation.columnType;
-      fieldResolvers.push({
-        returnTypeFunc,
-        rootArgType: entityName,
-        fieldName: f.name,
-        rootArgName: utils.camelCase(entityName),
-        returnType: utils.generateResolverReturnType(returnTypeFunc, f.isList),
-      });
-      fieldResolverImports.add(utils.generateEntityImport(returnTypeFunc));
-    }
-    const imports = Array.from(fieldResolverImports.values());
-    // If there is at least one field resolver then add typeorm to imports
-    imports.length ? imports.push(`import { getConnection } from 'typeorm';`) : null;
-    return {
-      fieldResolvers,
-      fieldResolverImports: imports,
-    };
-  }
-
-  transform(): GeneratorContext {
-    return {
-      ...this.context, //this.getGeneratedFolderRelativePath(objType.name),
-      ...this.withFields(),
-      ...this.withEnums(),
-      ...this.withInterfaces(),
-      ...this.withInterfaceProp(),
-      ...this.withHasProps(),
-      ...this.withSubclasses(),
-      ...this.withDescription(),
-      ...this.withImportProps(),
-      ...this.withFieldResolvers(),
-      ...utils.withNames(this.objType.name),
-    };
-  }
-}

+ 0 - 157
query-node/substrate-query-framework/cli/src/generate/RelationshipGenerator.ts

@@ -1,157 +0,0 @@
-import { WarthogModel, Field, ObjectType, makeRelation } from '../model';
-import { generateJoinColumnName, generateJoinTableName } from './utils';
-import { camelCase } from 'lodash';
-
-export class RelationshipGenerator {
-  private _visited: string[];
-  model: WarthogModel;
-
-  constructor(model: WarthogModel) {
-    this.model = model;
-    this._visited = [];
-  }
-
-  addMany2Many(field: Field, relatedField: Field, currentObject: ObjectType, relatedObject: ObjectType): void {
-    field.relation = makeRelation('mtm', field.type, relatedField.name);
-    field.relation.joinTable = {
-      tableName: generateJoinTableName(currentObject.name, relatedObject.name),
-      joinColumn: generateJoinColumnName(currentObject.name),
-      inverseJoinColumn: generateJoinColumnName(relatedObject.name),
-    };
-    relatedField.relation = makeRelation('mtm', relatedField.type, field.name);
-
-    this.addToVisited(...[currentObject.name.concat(field.name), relatedObject.name.concat(relatedField.name)]);
-  }
-
-  addOne2Many(field: Field, relatedField: Field, currentObject: ObjectType, relatedObject: ObjectType): void {
-    field.relation = makeRelation('otm', field.type, relatedField.name);
-    relatedField.relation = makeRelation('mto', relatedField.type, field.name);
-
-    this.addToVisited(...[currentObject.name.concat(field.name), relatedObject.name.concat(relatedField.name)]);
-  }
-
-  addMany2One(field: Field, currentObject: ObjectType, relatedObject: ObjectType, relatedField: Field): void {
-    if (!relatedField.type) {
-      // Additinal field for field resolver
-      const fname = camelCase(currentObject.name).concat('s');
-      relatedField = new Field(fname, relatedObject.name, field.nullable, false, true);
-      relatedField.relation = makeRelation('otm', currentObject.name, field.name);
-      relatedObject.fields.push(relatedField);
-    } else {
-      relatedField.relation = makeRelation('otm', currentObject.name, field.name);
-    }
-
-    field.relation = makeRelation('mto', field.type, relatedField.name);
-
-    this.addToVisited(...[currentObject.name.concat(field.name), relatedObject.name.concat(relatedField.name)]);
-  }
-
-  addOne2One(field: Field, relatedField: Field, currentObject: ObjectType, relatedObject: ObjectType): void {
-    field.relation = makeRelation('oto', field.type, relatedField.name);
-    field.relation.joinColumn = true;
-    relatedField.relation = makeRelation('oto', relatedField.type, field.name);
-
-    this.addToVisited(...[currentObject.name.concat(field.name), relatedObject.name.concat(relatedField.name)]);
-  }
-
-  addToVisited(...args: string[]): void {
-    this._visited.push(...args);
-  }
-
-  isVisited(f: Field, o: ObjectType): boolean {
-    return this._visited.includes(o.name.concat(f.name));
-  }
-
-  listTypeWithNoDerivedDirective(field: Field, currentObject: ObjectType): void {
-    const relatedObject = this.model.lookupEntity(field.type);
-    const relatedFields = relatedObject.fields.filter(f => f.type === currentObject.name && f.isList);
-
-    if (relatedFields.length !== 1) {
-      throw new Error(`Incorrect ManyToMany relationship detected! ${currentObject.name} -> ${field.name}
-            found ${relatedFields.length} fields on ${relatedObject.name} of list type`);
-    }
-    if (!relatedFields[0].derivedFrom) {
-      throw new Error(`Incorrect ManyToMany relationship detected! @derived directive
-            for ${relatedObject.name}->${relatedFields[0].name} not found`);
-    }
-    this.addMany2Many(field, relatedFields[0], currentObject, relatedObject);
-  }
-
-  listTypeWithDerivedDirective(field: Field, currentObject: ObjectType): void {
-    // Shoud never happen!
-    if (!field.derivedFrom) throw new Error(`No derivedFrom found on ${currentObject.name}->${field.name}`);
-
-    const relatedObject = this.model.lookupEntity(field.type);
-    const relatedField = this.model.lookupField(field.type, field.derivedFrom.argument);
-
-    if (relatedField.derivedFrom) {
-      throw new Error(
-        `${relatedObject.name}->${relatedField.name} derived field can not reference to another derived field!`
-      );
-    }
-
-    relatedField.isList
-      ? this.addMany2Many(field, relatedField, currentObject, relatedObject)
-      : this.addOne2Many(field, relatedField, currentObject, relatedObject);
-  }
-
-  typeWithDerivedDirective(field: Field, currentObject: ObjectType): void {
-    // Shoud never happen!
-    if (!field.derivedFrom) throw new Error(`No derivedFrom found on ${currentObject.name}->${field.name}`);
-
-    const relatedObject = this.model.lookupEntity(field.type);
-    const relatedField = this.model.lookupField(field.type, field.derivedFrom.argument);
-
-    if (relatedField.derivedFrom) {
-      throw new Error(
-        `${relatedObject.name}->${relatedField.name} derived field can not reference to another derived field!`
-      );
-    }
-    if (relatedField.isList) {
-      throw new Error(`${relatedObject.name}->${relatedField.name} can not reference to another a list field`);
-    }
-    this.addOne2One(field, relatedField, currentObject, relatedObject);
-  }
-
-  typeWithNoDerivedDirective(field: Field, currentObject: ObjectType): void {
-    const relatedObject = this.model.lookupEntity(field.type);
-    const relatedFields = relatedObject.fields.filter(f => f.type === currentObject.name);
-
-    if (relatedFields.length === 0) {
-      return this.addMany2One(field, currentObject, relatedObject, {} as Field);
-    }
-    const derivedFields = relatedFields.filter(f => f.derivedFrom?.argument === field.name);
-    if (derivedFields.length === 1) {
-      return !derivedFields[0].isList
-        ? this.addOne2One(field, derivedFields[0], currentObject, relatedObject)
-        : this.addMany2One(field, currentObject, relatedObject, derivedFields[0]);
-    }
-    // Errors
-    throw derivedFields.length === 0
-      ? new Error(
-          `Incorrect relationship. '${relatedObject.name}' should have a derived field 
-        with @derivedFrom(field: "${field.name}") directive maybe?`
-        )
-      : new Error(`Found multiple derived fields with same argument -> @derivedField(field:"${field.name}")`);
-  }
-
-  generate(): void {
-    const entityNames = this.model.entities.map(t => t.name);
-
-    this.model.entities.forEach(currentObject => {
-      for (const field of currentObject.fields) {
-        if (!entityNames.includes(field.type) || this.isVisited(field, currentObject)) continue;
-
-        if (field.isList) {
-          return field.derivedFrom
-            ? this.listTypeWithDerivedDirective(field, currentObject)
-            : this.listTypeWithNoDerivedDirective(field, currentObject);
-        } else {
-          return field.derivedFrom
-            ? this.typeWithDerivedDirective(field, currentObject)
-            : this.typeWithNoDerivedDirective(field, currentObject);
-        }
-      }
-    });
-  }
-}

+ 0 - 158
query-node/substrate-query-framework/cli/src/generate/SourcesGenerator.ts

@@ -1,158 +0,0 @@
-import * as fs from 'fs-extra';
-import * as path from 'path';
-import { getTemplatePath, createFile, createDir } from '../utils/utils';
-
-import Debug from 'debug';
-import { WarthogModel, ObjectType } from '../model';
-import { FTSQueryRenderer } from './FTSQueryRenderer';
-import { ModelRenderer } from './ModelRenderer';
-import { EnumRenderer } from './EnumRenderer';
-import { kebabCase } from './utils';
-import { ConfigProvider } from './ConfigProvider';
-import { EnumContextProvider } from './EnumContextProvider';
-import { VariantsRenderer } from './VariantsRenderer';
-
-const debug = Debug('qnode-cli:sources-generator');
-
-export const QUERIES_FOLDER = 'queries';
-export const ENUMS_FOLDER = 'enums';
-export const VARIANTS_FOLDER = 'variants';
-export const INTERFACES_FOLDER = 'interfaces';
-
-/**
- * additional context to be passed to the generator,
- * e.g. to have predictable timestamps
- */
-export interface GeneratorContext {
-  [key: string]: unknown;
-}
-
-export class SourcesGenerator {
-  readonly config: ConfigProvider;
-  readonly model: WarthogModel;
-
-  constructor(model: WarthogModel) {
-    this.config = new ConfigProvider();
-    this.model = model;
-  }
-
-  generate(): void {
-    this.generateEnums();
-    this.generateVariants();
-    this.generateModels();
-    this.generateQueries();
-  }
-
-  generateModels(): void {
-    createDir(path.resolve(process.cwd(), 'src/modules'), false, true);
-
-    const enumContextProvider = new EnumContextProvider();
-
-    const typesAndInterfaces: ObjectType[] = [...this.model.interfaces, ...this.model.entities];
-
-    typesAndInterfaces.map(objType => {
-      const context = this.config.withGeneratedFolderRelPath(objType.name);
-      const modelRenderer = new ModelRenderer(this.model, objType, enumContextProvider, context);
-      const destFolder = this.config.getDestFolder(objType.name);
-      createDir(path.resolve(process.cwd(), destFolder), false, true);
-
-      const tempateFile: { [key: string]: string } = {
-        model: 'entities/model.ts.mst',
-        resolver: objType.isInterface ? 'interfaces/resolver.ts.mst' : 'entities/resolver.ts.mst',
-        service: objType.isInterface ? 'interfaces/service.ts.mst' : 'entities/service.ts.mst',
-      };
-
-      ['model', 'resolver', 'service'].map(template => {
-        const rendered = modelRenderer.render(this.readTemplate(tempateFile[template]));
-        const destPath = path.join(destFolder, `${kebabCase(objType.name)}.${template}.ts`);
-        this.writeFile(destPath, rendered);
-      });
-    });
-  }
-
-  generateQueries(): void {
-    if (!this.model) {
-      throw new Error('Warthog model is undefined');
-    }
-
-    // create migrations dir if not exists
-    const migrationsDir = this.config.getMigrationsFolder();
-    fs.ensureDirSync(path.resolve(process.cwd(), migrationsDir));
-
-    // create dir if the textsearch module
-    const ftsDir = this.config.getDestFolder(QUERIES_FOLDER);
-    fs.ensureDirSync(path.resolve(process.cwd(), ftsDir));
-
-    const queryRenderer = new FTSQueryRenderer();
-
-    this.model.ftsQueries.map(query => {
-      const tempateFile = (name: string) => this.readTemplate(`textsearch/${name}.ts.mst`);
-      const destPath = {
-        migration: path.join(migrationsDir, `${query.name}.migration.ts`),
-        resolver: path.join(ftsDir, `${query.name}.resolver.ts`),
-        service: path.join(ftsDir, `${query.name}.service.ts`),
-      } as { [key: string]: string };
-
-      ['migration', 'resolver', 'service'].map(name => {
-        const rendered = queryRenderer.generate(tempateFile(name), query);
-        debug(`Writing ${query.name} ${name} to ${destPath[name]}`);
-        this.writeFile(destPath[name], rendered);
-      });
-    });
-  }
-
-  generateVariants(): void {
-    if (!this.model.unions) {
-      return;
-    }
-
-    const unionDir = this.config.getDestFolder(VARIANTS_FOLDER);
-    createDir(path.resolve(process.cwd(), unionDir), false, true);
-    const renderer = new VariantsRenderer(this.model);
-    const template = this.readTemplate('variants/variants.mst');
-    this.writeFile(path.join(unionDir, 'variants.model.ts'), renderer.render(template));
-  }
-
-  generateEnums(): void {
-    if (!this.model.enums) {
-      return;
-    }
-
-    const enumsDir = this.config.getDestFolder(ENUMS_FOLDER);
-    createDir(path.resolve(process.cwd(), enumsDir), false, true);
-
-    const enumRenderer = new EnumRenderer(this.model);
-    const rendered = enumRenderer.render(this.readTemplate('entities/enums.ts.mst'));
-    this.writeFile(path.join(enumsDir, `enums.ts`), rendered);
-  }
-
-  /**
-   *
-   * @param template relative path to a template from the templates folder, e.g. 'db-helper.mst'
-   * @param destPath relative path to the `generated/graphql-server' folder, e.g. 'src/index.ts'
-   * @param render function which transforms the template contents
-   */
-  private renderAndWrite(template: string, destPath: string, render: (data: string) => string) {
-    const templateData: string = fs.readFileSync(getTemplatePath(template), 'utf-8');
-    debug(`Source: ${getTemplatePath(template)}`);
-    const rendered: string = render(templateData);
-
-    debug(`Transformed: ${rendered}`);
-    const destFullPath = path.resolve(process.cwd(), destPath);
-
-    debug(`Writing to: ${destFullPath}`);
-    createFile(destFullPath, rendered, true);
-  }
-
-  private readTemplate(relPath: string) {
-    debug(`Reading template: ${relPath}`);
-    return fs.readFileSync(getTemplatePath(relPath), 'utf-8');
-  }
-
-  private writeFile(destPath: string, data: string) {
-    const destFullPath = path.resolve(process.cwd(), destPath);
-
-    debug(`Writing to: ${destFullPath}`);
-    createFile(destFullPath, data, true);
-  }
-}

+ 0 - 46
query-node/substrate-query-framework/cli/src/generate/VariantsRenderer.ts

@@ -1,46 +0,0 @@
-import { WarthogModel } from '../model';
-import { GeneratorContext } from './SourcesGenerator';
-import { AbstractRenderer } from './AbstractRenderer';
-import { ModelRenderer } from './ModelRenderer';
-import { EnumContextProvider } from './EnumContextProvider';
-import { withUnionType } from './union-context';
-
-export class VariantsRenderer extends AbstractRenderer {
-  
-  constructor(
-    model: WarthogModel,
-    context: GeneratorContext = {}
-  ) {
-    super(model, context);
-
-  }
-
-  withVariants(): GeneratorContext {
-    const variants: GeneratorContext[] = []
-    for (const v of this.model.variants) {
-      const renderer = new ModelRenderer(this.model, v, new EnumContextProvider(), {});
-      variants.push(renderer.transform());
-    }
-    return {
-      variants,
-    }
-  }
-
-
-  withUnions(): GeneratorContext {
-    const unions: GeneratorContext[] = [];
-    for (const u of this.model.unions) {
-      unions.push(withUnionType(u))
-    }
-    return {
-      unions,
-    }
-  }
-
-  transform(): GeneratorContext {
-    return {
-      ...this.withUnions(),
-      ...this.withVariants()
-    }
-  }
-}

+ 0 - 29
query-node/substrate-query-framework/cli/src/generate/enum-context.ts

@@ -1,29 +0,0 @@
-import { GraphQLEnumType } from 'graphql';
-import { GeneratorContext, ENUMS_FOLDER } from './SourcesGenerator';
-
-export function withEnum(enumType: GraphQLEnumType): GeneratorContext {
-  return {
-    ...withName(enumType),
-    ...withValues(enumType),
-  };
-}
-
-export function withName(enumType: GraphQLEnumType): GeneratorContext {
-  return {
-    name: enumType.name,
-  };
-}
-
-export function withValues(enumType: GraphQLEnumType): GeneratorContext {
-  const values: GeneratorContext[] = [];
-  enumType.getValues().map(v => values.push({ name: v.name, value: v.value as string }));
-  return {
-    values,
-  };
-}
-
-export function withRelativePathForEnum(): GeneratorContext {
-  return {
-    relativePath: `../${ENUMS_FOLDER}/enums`,
-  };
-}

+ 0 - 187
query-node/substrate-query-framework/cli/src/generate/field-context.ts

@@ -1,187 +0,0 @@
-import { GeneratorContext } from './SourcesGenerator';
-import { Field, ObjectType } from '../model';
-import * as util from './utils';
-import { withRelativePathForEnum } from './enum-context';
-
-export const TYPE_FIELDS: { [key: string]: { [key: string]: string } } = {
-  bool: {
-    decorator: 'BooleanField',
-    tsType: 'boolean',
-  },
-  date: {
-    decorator: 'DateField',
-    tsType: 'Date',
-  },
-  int: {
-    decorator: 'IntField',
-    tsType: 'number',
-  },
-  float: {
-    decorator: 'FloatField',
-    tsType: 'number',
-  },
-  json: {
-    decorator: 'JSONField',
-    tsType: 'JsonObject',
-  },
-  otm: {
-    decorator: 'OneToMany',
-    tsType: '---',
-  },
-  mto: {
-    decorator: 'ManyToOne',
-    tsType: '---',
-  },
-  mtm: {
-    decorator: 'ManyToMany',
-    tsType: '---',
-  },
-  string: {
-    decorator: 'StringField',
-    tsType: 'string',
-  },
-  numeric: {
-    decorator: 'NumericField',
-    tsType: 'BN',
-  },
-  decimal: {
-    decorator: 'NumericField',
-    tsType: 'BN',
-  },
-  oto: {
-    decorator: 'OneToOne',
-    tsType: '---',
-  },
-  array: {
-    decorator: 'ArrayField',
-    tsType: '', // will be updated with the correct type
-  },
-  bytes: {
-    decorator: 'BytesField',
-    tsType: 'Buffer',
-  },
-};
-
-const graphQLFieldTypes: { [key: string]: string } = {
-  bool: 'boolean',
-  int: 'integer',
-  string: 'string',
-  float: 'float',
-  date: 'date',
-  numeric: 'numeric',
-  decimal: 'numeric',
-};
-
-export function buildFieldContext(f: Field, entity: ObjectType): GeneratorContext {
-  return {
-    ...withFieldTypeGuardProps(f),
-    ...withRequired(f),
-    ...withUnique(f),
-    ...withRelation(f),
-    ...withArrayCustomFieldConfig(f),
-    ...withTsTypeAndDecorator(f),
-    ...withDerivedNames(f, entity),
-    ...withDescription(f),
-    ...withTransformer(f),
-  };
-}
-
-export function withFieldTypeGuardProps(f: Field): GeneratorContext {
-  const is: GeneratorContext = {};
-  is['array'] = f.isArray();
-  is['scalar'] = f.isScalar();
-  is['enum'] = f.isEnum();
-  is['union'] = f.isUnion();
-
-  ['mto', 'oto', 'otm', 'mtm'].map(s => (is[s] = f.relation?.type === s));
-  return {
-    is: is,
-  };
-}
-
-export function withRequired(f: Field): GeneratorContext {
-  return {
-    required: !f.nullable,
-  };
-}
-
-export function withDescription(f: Field): GeneratorContext {
-  return {
-    description: f.description,
-  };
-}
-
-export function withUnique(f: Field): GeneratorContext {
-  return {
-    unique: f.unique,
-  };
-}
-
-export function withTsTypeAndDecorator(f: Field): GeneratorContext {
-  const fieldType = f.columnType();
-  if (TYPE_FIELDS[fieldType]) {
-    return {
-      ...TYPE_FIELDS[fieldType],
-    };
-  }
-
-  return {
-    tsType: f.type,
-  };
-}
-
-export function withArrayCustomFieldConfig(f: Field): GeneratorContext {
-  if (!f.isArray()) {
-    return {};
-  }
-  const type = f.columnType();
-  const apiType = graphQLFieldTypes[type];
-
-  let dbType = apiType;
-  if (dbType === 'string') {
-    dbType = 'text'; // postgres doesnt have 'string'
-  } else if (dbType === 'float') {
-    dbType = 'decimal'; // postgres doesnt have 'float'
-  }
-
-  return {
-    dbType,
-    apiType,
-  };
-}
-
-export function withDerivedNames(f: Field, entity: ObjectType): GeneratorContext {
-  return {
-    ...util.names(f.name),
-    relFieldName: util.camelCase(entity.name),
-    relFieldNamePlural: util.camelPlural(entity.name),
-  };
-}
-
-export function withImport(f: Field): GeneratorContext {
-  if (!f.isEnum()) {
-    return {};
-  }
-  return {
-    className: f.type,
-    ...withRelativePathForEnum(),
-  };
-}
-
-export function withRelation(f: Field): GeneratorContext {
-  return {
-    relation: f.relation,
-  };
-}
-
-export function withTransformer(f: Field): GeneratorContext {
-  if (TYPE_FIELDS[f.columnType()] && TYPE_FIELDS[f.columnType()].tsType === 'BN') {
-    return {
-      transformer: `{
-        to: (entityValue: BN) => (entityValue !== undefined) ? entityValue.toString(10) : null,
-        from: (dbValue: string) => dbValue !== undefined && dbValue !== null && dbValue.length > 0 ? new BN(dbValue, 10): undefined,
-      }`,
-    };
-  }
-  return {};
-}

+ 0 - 30
query-node/substrate-query-framework/cli/src/generate/union-context.ts

@@ -1,30 +0,0 @@
-import { GeneratorContext, VARIANTS_FOLDER } from './SourcesGenerator';
-import { UnionType } from '../model/WarthogModel';
-import { withNames } from './utils';
-
-export function withUnionType(unionType: UnionType): GeneratorContext {
-  return {
-    ...withName(unionType),
-    ...withTypes(unionType),
-  };
-}
-
-export function withName(unionType: UnionType): GeneratorContext {
-  return {
-    name: unionType.name,
-  };
-}
-
-export function withTypes(unionType: UnionType): GeneratorContext {
-  const types: GeneratorContext[] = [];
-  unionType.types.map(t => types.push(withNames(t.name)));
-  return {
-    types,
-  };
-}
-
-export function withRelativePathForUnions(): GeneratorContext {
-  return {
-    relativePath: `../${VARIANTS_FOLDER}/unions`,
-  };
-}

+ 0 - 77
query-node/substrate-query-framework/cli/src/generate/utils.ts

@@ -1,77 +0,0 @@
-import { upperFirst, kebabCase, camelCase, snakeCase } from 'lodash';
-import { GeneratorContext } from './SourcesGenerator';
-import { ObjectType, Field } from '../model';
-import _ from 'lodash';
-
-export { upperFirst, kebabCase, camelCase };
-/* eslint-disable @typescript-eslint/no-unsafe-member-access */
-/* eslint-disable @typescript-eslint/no-unsafe-assignment */
-export function supplant(str: string, obj: Record<string, unknown>): string {
-  return str.replace(/\${([^${}]*)}/g, (a, b) => {
-    const r = obj[b];
-    return typeof r === 'string' ? r : a;
-  });
-}
-
-export function pascalCase(str: string): string {
-  return upperFirst(camelCase(str));
-}
-
-export function camelPlural(str: string): string {
-  return `${camelCase(str)}s`;
-}
-
-export function names(name: string): { [key: string]: string } {
-  return {
-    className: pascalCase(name),
-    camelName: camelCase(name),
-    kebabName: kebabCase(name),
-    relClassName: pascalCase(name),
-    relCamelName: camelCase(name),
-    // Not proper pluralization, but good enough and easy to fix in generated code
-    camelNamePlural: camelPlural(name),
-  };
-}
-
-export function withNames(name: string): GeneratorContext {
-  return {
-    name,
-    ...names(name),
-  };
-}
-
-export function hasInterfaces(o: ObjectType): boolean {
-  if (o.interfaces == undefined) {
-    return false;
-  }
-  return o.interfaces.length > 0;
-}
-
-/**
- * Return fields which are not definded in the interface
- * @param o ObjecType definition
- */
-export function ownFields(o: ObjectType): Field[] {
-  if (!hasInterfaces(o) || o.interfaces == undefined) {
-    return o.fields;
-  }
-
-  const intrFields = o.interfaces[0].fields || [];
-  return _.differenceBy(o.fields, intrFields, 'name');
-}
-export function generateJoinColumnName(name: string): string {
-  return snakeCase(name.concat('_id'));
-}
-
-export function generateJoinTableName(table1: string, table2: string): string {
-  return snakeCase(table1.concat('_', table2));
-}
-
-export function generateEntityImport(entityName: string): string {
-  const kebabName = kebabCase(entityName);
-  return `import {${entityName}} from '../${kebabName}/${kebabName}.model'`;
-}
-
-export function generateResolverReturnType(type: string, isList: boolean): string {
-  return `Promise<${type}${isList ? '[]' : ''}>`;
-}

+ 0 - 190
query-node/substrate-query-framework/cli/src/helpers/WarthogWrapper.ts

@@ -1,190 +0,0 @@
-import * as fs from 'fs-extra';
-import * as path from 'path';
-import * as dotenv from 'dotenv';
-import execa = require('execa');
-
-import Command from '@oclif/command';
-import { run } from 'warthog/dist/cli/cli';
-
-import { WarthogModelBuilder } from './../parse/WarthogModelBuilder';
-import { getTemplatePath } from '../utils/utils';
-import Debug from 'debug';
-import { SourcesGenerator } from '../generate/SourcesGenerator';
-import Listr = require('listr');
-
-const debug = Debug('qnode-cli:warthog-wrapper');
-
-export default class WarthogWrapper {
-  private readonly command: Command;
-  private readonly schemaPath: string;
-  private readonly schemaResolvedPath: string;
-
-  constructor(command: Command, schemaPath: string) {
-    this.command = command;
-    this.schemaPath = schemaPath;
-    this.schemaResolvedPath = path.resolve(process.cwd(), this.schemaPath);
-    if (!fs.existsSync(this.schemaResolvedPath)) {
-      throw new Error(`Cannot open the schema file ${this.schemaResolvedPath}. Check if it exists.`);
-    }
-  }
-
-  async run(): Promise<void> {
-    // Order of calling functions is important!!!
-    const tasks = new Listr([
-      {
-        title: 'Set up a new Warthog project',
-        task: async () => {
-          await this.newProject();
-        },
-      },
-      {
-        title: 'Install GraphQL server dependencies',
-        task: async () => {
-          await this.installDependencies();
-        },
-      },
-      {
-        title: 'Generate server sources',
-        task: () => {
-          this.generateWarthogSources();
-        },
-      },
-      {
-        title: 'Warthog codegen',
-        task: async () => {
-          await this.codegen();
-        },
-      },
-    ]);
-
-    await tasks.run();
-  }
-
-  async generateDB(): Promise<void> {
-    const tasks = new Listr([
-      {
-        title: 'Create database',
-        task: async () => {
-          if (!process.env.DB_NAME) {
-            throw new Error('DB_NAME env variable is not set, check that .env file exists');
-          }
-          await this.createDB();
-        },
-      },
-      {
-        title: 'Generate migrations',
-        task: async () => {
-          await this.createMigrations();
-        },
-      },
-      {
-        title: 'Run migrations',
-        task: async () => {
-          await this.runMigrations();
-        },
-      },
-    ]);
-    await tasks.run();
-  }
-
-  async generateAPIPreview(): Promise<void> {
-    // Order of calling functions is important!!!
-    await this.newProject();
-    await this.installDependencies();
-    this.generateWarthogSources();
-    await this.codegen();
-  }
-
-  async newProject(projectName = 'query_node'): Promise<void> {
-    const consoleFn = console.log;
-    console.log = () => {
-      return;
-    };
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-    await run(['new', `${projectName}`]);
-    console.log = consoleFn;
-
-    // Override warthog's index.ts file for custom naming strategy
-    fs.copyFileSync(getTemplatePath('graphql-server.index.mst'), path.resolve(process.cwd(), 'src/index.ts'));
-
-    await this.updateDotenv();
-  }
-
-  async installDependencies(): Promise<void> {
-    if (!fs.existsSync('package.json')) {
-      this.command.error('Could not found package.json file in the current working directory');
-    }
-
-    // Temporary tslib fix
-    const pkgFile = JSON.parse(fs.readFileSync('package.json', 'utf8')) as Record<string, Record<string, unknown>>;
-    pkgFile.resolutions['tslib'] = '1.11.2';
-    pkgFile.scripts['db:sync'] = 'SYNC=true WARTHOG_DB_SYNCHRONIZE=true ts-node --type-check src/index.ts';
-
-    // Fix ts-node-dev error
-    pkgFile.scripts['start:dev'] = 'ts-node --type-check src/index.ts';
-
-    // Node does not run the compiled code, so we use ts-node in production...
-    pkgFile.scripts['start:prod'] = 'WARTHOG_ENV=production yarn dotenv:generate && ts-node src/index.ts';
-
-    fs.writeFileSync('package.json', JSON.stringify(pkgFile, null, 2));
-
-    //this.command.log('Installing graphql-server dependencies...');
-    await execa('yarn', ['add', 'lodash']); // add lodash dep
-    await execa('yarn', ['install']);
-
-    //this.command.log('done...');
-  }
-
-  async createDB(): Promise<void> {
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
-    await run(['db:create']);
-  }
-
-  /**
-   * Generate the warthog source files:
-   *   - model/resolver/service for entities
-   *   - Fulltext search queries (migration/resolver/service)
-   */
-  generateWarthogSources(): void {
-    const modelBuilder = new WarthogModelBuilder(this.schemaResolvedPath);
-    const model = modelBuilder.buildWarthogModel();
-
-    const sourcesGenerator = new SourcesGenerator(model);
-    sourcesGenerator.generate();
-  }
-
-  async codegen(): Promise<void> {
-    await execa('yarn', ['warthog', 'codegen']);
-    await execa('yarn', ['dotenv:generate']);
-  }
-
-  async createMigrations(): Promise<void> {
-    await execa('yarn', ['db:sync']);
-  }
-
-  async runMigrations(): Promise<void> {
-    debug('performing migrations');
-    await execa('yarn', ['db:migrate']);
-  }
-
-  async updateDotenv(): Promise<void> {
-    // copy dotnenvi env.yml file
-    debug('Creating graphql-server/env.yml');
-    await fs.copyFile(getTemplatePath('warthog.env.yml'), path.resolve(process.cwd(), 'env.yml'));
-    const envConfig = dotenv.parse(fs.readFileSync('.env'));
-
-    // Override DB_NAME, PORT, ...
-    envConfig['WARTHOG_DB_DATABASE'] = process.env.DB_NAME || envConfig['WARTHOG_DB_DATABASE'];
-    envConfig['WARTHOG_DB_USERNAME'] = process.env.DB_USER || envConfig['WARTHOG_DB_USERNAME'];
-    envConfig['WARTHOG_DB_PASSWORD'] = process.env.DB_PASS || envConfig['WARTHOG_DB_PASSWORD'];
-    envConfig['WARTHOG_DB_HOST'] = process.env.DB_HOST || envConfig['WARTHOG_DB_HOST'];
-    envConfig['WARTHOG_DB_PORT'] = process.env.DB_PORT || envConfig['WARTHOG_DB_PORT'];
-    envConfig['WARTHOG_APP_PORT'] = process.env.GRAPHQL_SERVER_PORT || envConfig['WARTHOG_APP_PORT'];
-    envConfig['WARTHOG_APP_HOST'] = process.env.GRAPHQL_SERVER_HOST || envConfig['WARTHOG_APP_HOST'];
-
-    const newEnvConfig = Object.keys(envConfig)
-      .map(key => `${key}=${envConfig[key]}`)
-      .join('\n');
-    await fs.writeFile('.env', newEnvConfig);
-  }
-}

+ 0 - 47
query-node/substrate-query-framework/cli/src/helpers/db.ts

@@ -1,47 +0,0 @@
-import * as dotenv from 'dotenv';
-import * as fs from 'fs-extra';
-import { createConnection, getConnection } from 'typeorm';
-
-import { getTemplatePath } from '../utils/utils';
-
-/**
- * Update typeorms' .env config file with top level .env file
- */
-export function getTypeormConfig(): string {
-  const envConfig = dotenv.parse(fs.readFileSync(getTemplatePath('dotenv-ormconfig.mst')));
-
-  envConfig['TYPEORM_DATABASE'] = process.env.DB_NAME || envConfig['TYPEORM_DATABASE'];
-  envConfig['TYPEORM_USERNAME'] = process.env.DB_USER || envConfig['TYPEORM_USERNAME'];
-  envConfig['TYPEORM_PASSWORD'] = process.env.DB_PASS || envConfig['TYPEORM_PASSWORD'];
-  envConfig['TYPEORM_HOST'] = process.env.DB_HOST || envConfig['TYPEORM_HOST'];
-  envConfig['TYPEORM_PORT'] = process.env.DB_PORT || envConfig['TYPEORM_PORT'];
-
-  const newEnvConfig = Object.keys(envConfig)
-    .map(key => `${key}=${envConfig[key]}`)
-    .join('\n');
-  return newEnvConfig;
-}
-
-export async function resetLastProcessedEvent(): Promise<void> {
-  await createConnection();
-  // get a connection and create a new query runner
-  const queryRunner = getConnection().createQueryRunner();
-
-  // establish real database connection using our new query runner
-  await queryRunner.connect();
-  const lastProcessedEvent = {
-    blockNumber: 0,
-    eventName: 'ExtrinsicSuccess',
-    index: 0,
-  };
-
-  // now we can execute any queries on a query runner
-  await queryRunner.query(
-    `UPDATE saved_entity_event SET 
-    "blockNumber" = ${lastProcessedEvent.blockNumber}, 
-    index = ${lastProcessedEvent.index},
-    "eventName" = '${lastProcessedEvent.eventName}';`
-  );
-
-  await queryRunner.release();
-}

+ 0 - 17
query-node/substrate-query-framework/cli/src/helpers/formatter.ts

@@ -1,17 +0,0 @@
-import * as Prettier from 'prettier';
-
-const prettierOptions: Prettier.Options = {
-  parser: 'typescript',
-  endOfLine: 'auto',
-};
-
-export function formatWithPrettier(text: string, options: Prettier.Options = prettierOptions):string {
-  let formatted = '';
-  try {
-    formatted = Prettier.format(text, options);
-  } catch (error) {
-    console.error('There were some errors while formatting with Prettier', error);
-    formatted = text;
-  }
-  return formatted;
-}

+ 0 - 17
query-node/substrate-query-framework/cli/src/helpers/tsTypes.ts

@@ -1,17 +0,0 @@
-export const fieldTypes: { [key: string]: { [key: string]: string } } = {
-  bool: {
-    tsType: 'boolean',
-  },
-  date: {
-    tsType: 'Date',
-  },
-  int: {
-    tsType: 'number',
-  },
-  float: {
-    tsType: 'number',
-  },
-  string: {
-    tsType: 'string',
-  },
-};

+ 0 - 10
query-node/substrate-query-framework/cli/src/index.ts

@@ -1,10 +0,0 @@
-// import { build } from 'gluegun';
-
-// export const cli = build()
-//     .brand('warthog')
-//     .src(`${__dirname}/../node_modules/warthog/dist/cli`)
-//     .help() // provides default for help, h, --help, -h
-//     .version() // provides default for version, v, --version, -v
-//     .create();
-
-// export { run } from '@oclif/command'

+ 0 - 21
query-node/substrate-query-framework/cli/src/model/FTSQuery.ts

@@ -1,21 +0,0 @@
-import { ObjectType, Field } from '.';
-
-/**
- * FTSQueryClause represents a single entity/field which
- * corresponds to a text-based table column in the corresponding database schema.
- *
- * The clauses are concatenated and stored in a separated db view;
- */
-export interface FTSQueryClause {
-  entity: ObjectType;
-  field: Field;
-}
-
-/**
- * Represnts Fulltext search query as defined by
- *  fields in GraphGL  decorated FTSDirective directive
- */
-export interface FTSQuery {
-  name: string;
-  clauses: FTSQueryClause[];
-}

+ 0 - 72
query-node/substrate-query-framework/cli/src/model/Field.ts

@@ -1,72 +0,0 @@
-import { Relation } from '.';
-import { availableTypes } from './ScalarTypes';
-import { ModelType } from './WarthogModel';
-
-interface DerivedFrom {
-  argument: string;
-}
-
-/**
- * Reperenst GraphQL object type field
- * @constructor(name: string, type: string, nullable: boolean = true, isBuildinType: boolean = true, isList = false)
- */
-export class Field {
-  // GraphQL field name
-  name: string;
-  // GraphQL field type
-  type: string;
-  // type in the model (SCALAR, ENUM, INTERFACE, ENTITY, VARIANT)
-  modelType!: ModelType;
-  // Is field type built-in or not
-  isBuildinType: boolean;
-  // Is field nullable or not
-  nullable: boolean;
-  // Is field a list. eg: post: [Post]
-  isList: boolean;
-  // Description of the field will be shown in GrapqQL API
-  description?: string;
-  // Make field as a unique column on database
-  unique?: boolean;
-
-  // Relation
-  relation?: Relation;
-
-  derivedFrom?: DerivedFrom;
-
-  constructor(name: string, type: string, nullable = true, isBuildinType = true, isList = false) {
-    this.name = name;
-    this.type = type;
-    this.nullable = nullable;
-    this.isBuildinType = isBuildinType;
-    this.isList = isList;
-  }
-
-  // get isBuiltInType(): boolean {
-  //   return this.modelType == ModelType.SCALAR
-  // }
-
-  columnType(): string {
-    if (this.relation) return this.relation?.type;
-    return this.isBuildinType ? availableTypes[this.type] : this.type;
-  }
-
-  isArray(): boolean {
-    return this.isBuildinType && this.isList;
-  }
-
-  isScalar(): boolean {
-    return this.isBuildinType && !this.isList;
-  }
-
-  isRelationType(): boolean {
-    return this.relation ? true : false;
-  }
-
-  isEnum(): boolean {
-    return this.modelType == ModelType.ENUM;
-  }
-
-  isUnion(): boolean {
-    return this.modelType == ModelType.UNION;
-  }
-}

+ 0 - 15
query-node/substrate-query-framework/cli/src/model/ObjectType.ts

@@ -1,15 +0,0 @@
-import { Field } from '.';
-
-/**
- * Reperesent GraphQL object type
- */
-export interface ObjectType {
-  name: string;
-  fields: Field[];
-  isEntity: boolean;
-  isVariant: boolean;
-  // Description of the field will be shown in GrapqQL API
-  description?: string;
-  isInterface?: boolean;
-  interfaces?: ObjectType[]; //interface names
-}

+ 0 - 39
query-node/substrate-query-framework/cli/src/model/Relation.ts

@@ -1,39 +0,0 @@
-interface JoinTable {
-  tableName: string;
-  joinColumn: string;
-  inverseJoinColumn: string;
-}
-
-export interface Relation {
-  // Relation type oto, otm, mtm
-  type: string;
-
-  // Column type
-  columnType: string;
-
-  // Table that will hold relation id (foreign key)
-  joinColumn?: boolean;
-
-  joinTable?: JoinTable;
-
-  relatedTsProp?: string;
-}
-
-/**
- * Field resolver for related fields
- */
-export interface FieldResolver {
-  returnTypeFunc: string;
-  fieldName: string;
-  rootArgName: string;
-  rootArgType: string;
-  returnType: string;
-}
-
-export function makeRelation(type: string, columnType: string, relatedTsProp: string): Relation {
-  return {
-    type,
-    columnType,
-    relatedTsProp,
-  };
-}

+ 0 - 16
query-node/substrate-query-framework/cli/src/model/ScalarTypes.ts

@@ -1,16 +0,0 @@
-export interface ScalarType {
-  [name: string]: string;
-}
-
-// Supported built-in scalar types and corressponding warthog type
-export const availableTypes: ScalarType = {
-  ID: 'string',
-  String: 'string',
-  Int: 'int',
-  Boolean: 'bool',
-  Date: 'date',
-  Float: 'float',
-  BigInt: 'numeric',
-  BigDecimal: 'decimal',
-  Bytes: 'bytes',
-};

+ 0 - 249
query-node/substrate-query-framework/cli/src/model/WarthogModel.ts

@@ -1,249 +0,0 @@
-import { GraphQLEnumType } from 'graphql';
-import Debug from 'debug';
-import { validateVariantField } from './validate';
-import { availableTypes } from './ScalarTypes';
-
-const debug = Debug('qnode-cli:model');
-
-export enum ModelType {
-  ENUM,
-  VARIANT,
-  ENTITY,
-  UNION,
-  INTERFACE,
-  SCALAR,
-}
-
-import { ObjectType, Field, FTSQuery } from '.';
-
-export class WarthogModel {
-  private _entities: ObjectType[];
-  private _ftsQueries: FTSQuery[];
-  private _enums: GraphQLEnumType[] = [];
-  private _interfaces: ObjectType[] = [];
-  private _variants: ObjectType[] = [];
-  private _unions: UnionType[] = [];
-  private _name2query: { [key: string]: FTSQuery } = {};
-  private _name2type: { [key: string]: ObjectType } = {};
-
-  constructor() {
-    this._entities = [];
-    this._ftsQueries = [];
-  }
-
-  addUnion(name: string, typeNames: string[]): void {
-    const types: ObjectType[] = [];
-    typeNames.map(t => types.push(this.lookupVariant(t)));
-    this._unions.push({
-      name,
-      types,
-    });
-  }
-
-  addVariant(type: ObjectType): void {
-    if (!type.isVariant) {
-      debug(`${type.name} is not an Entity`);
-      return;
-    }
-
-    if (type.isEntity) {
-      throw new Error('An entity cannot be a variant');
-    }
-
-    type.fields.forEach(f => {
-      validateVariantField(f);
-    });
-
-    this._variants.push(type);
-  }
-
-  addEntity(type: ObjectType): void {
-    if (!type.isEntity) {
-      debug(`${type.name} is not an Entity`);
-      return;
-    }
-
-    this._entities.push(type);
-    this._name2type[type.name] = type;
-  }
-
-  addFTSQuery(query: FTSQuery): void {
-    if (!this._name2query[query.name]) {
-      this._name2query[query.name] = query;
-    }
-    this._ftsQueries.push(query);
-  }
-
-  addInterface(_interface: ObjectType): void {
-    this._interfaces.push(_interface);
-  }
-
-  addEnum(_enum: GraphQLEnumType): void {
-    this._enums.push(_enum);
-  }
-  /**
-   * Add emply full text search query with the given name
-   *
-   * @param name query name to be added
-   */
-  addEmptyFTSQuery(name: string): FTSQuery {
-    const query = {
-      name,
-      clauses: [],
-    };
-    this.addFTSQuery(query);
-    return query;
-  }
-
-  private _addQueryClause(name: string, f: Field, t: ObjectType): void {
-    let q: FTSQuery = this._name2query[name];
-    if (!q) {
-      q = this.addEmptyFTSQuery(name);
-    }
-    q.clauses.push({
-      entity: t,
-      field: f,
-    });
-  }
-
-  /**
-   * Add text search field to the named FTS query
-   *
-   * @param queryName fulltext query name
-   * @param fieldName name of the field to be added to the query
-   * @param typeName  objectType which defined that field
-   */
-  addQueryClause(queryName: string, fieldName: string, typeName: string): void {
-    const field = this.lookupField(typeName, fieldName);
-    const objType = this.lookupEntity(typeName);
-    this._addQueryClause(queryName, field, objType);
-  }
-
-  get entities(): ObjectType[] {
-    return this._entities;
-  }
-
-  get ftsQueries(): FTSQuery[] {
-    return this._ftsQueries;
-  }
-
-  get enums(): GraphQLEnumType[] {
-    return this._enums;
-  }
-
-  get interfaces(): ObjectType[] {
-    return this._interfaces;
-  }
-
-  get variants(): ObjectType[] {
-    return this._variants;
-  }
-
-  get unions(): UnionType[] {
-    return this._unions;
-  }
-
-  /**
-   * Lookup ObjectType by it's name (as defined in the schema file)
-   *
-   * @param name ObjectTypeName as defined in the schema
-   */
-  lookupEntity(name: string): ObjectType {
-    if (!this._name2type[name]) {
-      throw new Error(`Entity ${name} is undefined. Make sure the type definition is decorated with @entity.`);
-    }
-    return this._name2type[name];
-  }
-
-  lookupUnion(name: string): UnionType {
-    const u = this._unions.find(u => u.name === name);
-    if (!u) throw new Error(`Cannot find union type with name ${name}`);
-    return u;
-  }
-
-  lookupEnum(name: string): GraphQLEnumType {
-    const e = this._enums.find(e => e.name === name);
-    if (!e) throw new Error(`Cannot find enum with name ${name}`);
-    return e;
-  }
-
-  lookupVariant(name: string): ObjectType {
-    const e = this._variants.find(e => e.name === name);
-    if (!e) throw new Error(`Variant ${name} is undefined. Make sure the type definition is decorated with @variant.`);
-    return e;
-  }
-
-  lookupInterface(name: string): ObjectType {
-    const e = this._interfaces.find(e => e.name === name);
-    if (!e) throw new Error(`Cannot find interface with name ${name}`);
-    return e;
-  }
-
-  lookupQuery(queryName: string): FTSQuery {
-    if (!this._name2query) {
-      throw new Error(`No query with name ${queryName} found`);
-    }
-    return this._name2query[queryName];
-  }
-
-  /**
-   * Get subclasses of a given interface
-   *
-   * @param interfaceName Name of the interface
-   */
-  getSubclasses(interfaceName: string): ObjectType[] {
-    return this._entities.filter(t => t.interfaces && t.interfaces.length > 0 && t.interfaces[0].name == interfaceName);
-  }
-
-  /**
-   * Lookup Warthog's Field model object by it's ObjectType and name
-   *
-   * @param objTypeName Type name with the given field defined
-   * @param name the name of the field
-   */
-  lookupField(objTypeName: string, name: string): Field {
-    const objType = this.lookupEntity(objTypeName);
-    const field = objType.fields.find(f => f.name === name);
-    if (!field) {
-      throw new Error(`No field ${name} is found for object type ${objTypeName}`);
-    }
-    return field;
-  }
-
-  addField(entity: string, field: Field): void {
-    const objType = this.lookupEntity(entity);
-    objType.fields.push(field);
-  }
-
-  lookupType(name: string): ModelType {
-    if (name in availableTypes) {
-      return ModelType.SCALAR;
-    }
-
-    if (this._name2type[name]) {
-      return ModelType.ENTITY;
-    }
-
-    if (this._interfaces.find(i => i.name === name)) {
-      return ModelType.INTERFACE;
-    }
-
-    if (this._variants.find(v => v.name === name)) {
-      return ModelType.VARIANT;
-    }
-
-    if (this._unions.find(u => u.name === name)) {
-      return ModelType.UNION;
-    }
-
-    if (this._enums.find(e => e.name === name)) {
-      return ModelType.ENUM;
-    }
-    throw new Error(`Type ${name} is undefined`);
-  }
-}
-
-export interface UnionType {
-  name: string;
-  types: ObjectType[];
-}

+ 0 - 7
query-node/substrate-query-framework/cli/src/model/index.ts

@@ -1,7 +0,0 @@
-import { Field } from './Field';
-import { Relation, makeRelation, FieldResolver } from './Relation';
-import { FTSQuery } from './FTSQuery';
-import { WarthogModel, UnionType } from './WarthogModel';
-import { ObjectType } from './ObjectType';
-
-export { FTSQuery, WarthogModel, UnionType, ObjectType, Field, Relation, makeRelation, FieldResolver };

+ 0 - 8
query-node/substrate-query-framework/cli/src/model/validate.ts

@@ -1,8 +0,0 @@
-import { Field } from '.';
-
-export function validateVariantField(f: Field):void {
-  if (f.isRelationType()) {
-    throw new Error(`Reference types are not supported in varaints`);
-  } 
-}
-

+ 0 - 36
query-node/substrate-query-framework/cli/src/parse/DerivedFromDirective.ts

@@ -1,36 +0,0 @@
-import { FieldDefinitionNode, StringValueNode } from 'graphql';
-import { Field, WarthogModel } from '../model';
-import { DERIVED_FROM_DIRECTIVE } from './constant';
-
-export function addDerivedFromIfy(fieldDef: FieldDefinitionNode, field: Field): void {
-  const d = fieldDef.directives?.find(d => d.name.value === DERIVED_FROM_DIRECTIVE);
-  if (!d) return;
-
-  if (!d.arguments) {
-    throw new Error(`@${DERIVED_FROM_DIRECTIVE} should have a field argument`);
-  }
-
-  const directiveArgs = d.arguments.find(arg => arg.name.value === 'field' && arg.value.kind === 'StringValue');
-
-  // TODO: graphql-js already throw error??
-  if (!directiveArgs) {
-    throw new Error(`@${DERIVED_FROM_DIRECTIVE} should have a single field argument with a sting value`);
-  }
-
-  field.derivedFrom = { argument: (directiveArgs.value as StringValueNode).value };
-}
-
-export function validateDerivedFields(model: WarthogModel): void {
-  model.entities.forEach(objType => {
-    objType.fields.forEach(f => {
-      if (!f.derivedFrom) return;
-
-      if (f.isScalar()) {
-        throw new Error('Derived field type is not an entity type');
-      }
-      if (!model.lookupField(f.type, f.derivedFrom?.argument)) {
-        throw new Error('Derived field does not exists on the related type');
-      }
-    });
-  });
-}

+ 0 - 91
query-node/substrate-query-framework/cli/src/parse/FTSDirective.ts

@@ -1,91 +0,0 @@
-import { SchemaNode } from './SchemaParser';
-import { SchemaDirective } from './SchemaDirective';
-import { cloneDeep } from 'lodash';
-import { WarthogModel } from '../model';
-import {
-  DirectiveNode,
-  TypeNode,
-  ArgumentNode,
-  StringValueNode,
-  FieldDefinitionNode,
-  ObjectTypeDefinitionNode,
-} from 'graphql';
-
-export const FULL_TEXT_SEARCHABLE_DIRECTIVE = 'fulltext';
-
-export class FTSDirective implements SchemaDirective {
-  preamble = `directive @${FULL_TEXT_SEARCHABLE_DIRECTIVE}(query: String!) on FIELD_DEFINITION`;
-  name = FULL_TEXT_SEARCHABLE_DIRECTIVE;
-
-  validate(_path: SchemaNode[]): void {
-    const path = cloneDeep(_path);
-
-    if (path.length < 3) {
-      throw new Error(
-        'The path should contain at least a type and field definition nodes'
-      );
-    }
-    const dirNode = path.pop();
-    if (dirNode?.kind !== 'Directive') {
-      throw new Error('The path should end at a directive node');
-    }
-    const fieldNode = path.pop();
-    if (fieldNode?.kind !== 'FieldDefinition') {
-      throw new Error('The directive should be applied to a field node');
-    }
-    let type: TypeNode = fieldNode.type;
-    if (fieldNode.type.kind === 'NonNullType') {
-      type = fieldNode.type.type;
-    }
-    if (type.kind == 'ListType') {
-      throw new Error('Only single named types are supported');
-    }
-    if (type.kind !== 'NamedType') {
-      throw new Error('Only single named types are supported');
-    }
-    if (type.name.value !== 'String') {
-      throw new Error(
-        `Only string types can be annotaed ${FULL_TEXT_SEARCHABLE_DIRECTIVE}`
-      );
-    }
-  }
-
-  generate(path: SchemaNode[], model: WarthogModel): WarthogModel {
-    this.validate(path);
-
-    const dirNode = path.pop() as DirectiveNode;
-    const fieldNode = path.pop() as FieldDefinitionNode;
-    const objTypeNode = path.pop() as ObjectTypeDefinitionNode;
-
-    const qName: string = this._checkFullTextSearchDirective(dirNode);
-    model.addQueryClause(qName, fieldNode.name.value, objTypeNode.name.value);
-
-    return model;
-  }
-
-  /**
-   *
-   * Does the checks and returns full text query names to be used;
-   *
-   * @param d Directive Node
-   * @returns Fulltext query names
-   */
-  private _checkFullTextSearchDirective(d: DirectiveNode): string {
-    if (!d.arguments) {
-      throw new Error(
-        `@${FULL_TEXT_SEARCHABLE_DIRECTIVE} should have a query argument`
-      );
-    }
-
-    const qarg: ArgumentNode[] = d.arguments.filter(
-      (arg) => arg.name.value === `query` && arg.value.kind === `StringValue`
-    );
-
-    if (qarg.length !== 1) {
-      throw new Error(
-        `@${FULL_TEXT_SEARCHABLE_DIRECTIVE} should have a single query argument with a sting value`
-      );
-    }
-    return (qarg[0].value as StringValueNode).value;
-  }
-}

+ 0 - 28
query-node/substrate-query-framework/cli/src/parse/SchemaDirective.ts

@@ -1,28 +0,0 @@
-import { SchemaNode } from './SchemaParser';
-import { WarthogModel } from '../model';
-
-export const FULL_TEXT_SEARCHABLE_DIRECTIVE = 'fulltext';
-
-export interface DirectiveVisitor {
-  // directive name to watch
-  directiveName: string;
-  /**
-   * Generic visit function for the AST schema traversal.
-   * Only ObjectTypeDefinition and FieldDefinition nodes are included in the path during the
-   * traversal
-   *
-   * May throw validation errors
-   *
-   * @param path: BFS path in the schema tree ending at the directive node of interest
-   */
-  visit: (path: SchemaNode[]) => void;
-}
-
-export interface SchemaDirective {
-  // directive definition to be added to the
-  // schema preamble
-  preamble: string;
-  name: string;
-  validate: (path: SchemaNode[]) => void;
-  generate: (path: SchemaNode[], model: WarthogModel) => WarthogModel;
-}

+ 0 - 174
query-node/substrate-query-framework/cli/src/parse/SchemaParser.ts

@@ -1,174 +0,0 @@
-import {
-  parse,
-  visit,
-  buildASTSchema,
-  GraphQLSchema,
-  validateSchema,
-  ObjectTypeDefinitionNode,
-  FieldDefinitionNode,
-  DirectiveNode,
-  GraphQLEnumType,
-  GraphQLInterfaceType,
-  InterfaceTypeDefinitionNode,
-  GraphQLUnionType,
-  GraphQLNamedType,
-} from 'graphql';
-import * as fs from 'fs-extra';
-import Debug from 'debug';
-import { cloneDeep } from 'lodash';
-import { SCHEMA_DEFINITIONS_PREAMBLE } from './constant';
-import { SchemaDirective } from './SchemaDirective';
-import { FTSDirective } from './FTSDirective';
-
-const debug = Debug('qnode-cli:schema-parser');
-
-export const DIRECTIVES: SchemaDirective[] = [new FTSDirective()];
-
-export type SchemaNode = ObjectTypeDefinitionNode | FieldDefinitionNode | DirectiveNode;
-
-export interface Visitor {
-  /**
-   * Generic visit function for the AST schema traversal.
-   * Only ObjectTypeDefinition and FieldDefinition nodes are included in the path during the
-   * traversal
-   *
-   * May throw validation errors
-   *
-   * @param path: DFS path in the schema tree ending at the directive node of interest
-   */
-  visit: (path: SchemaNode[]) => void;
-}
-
-export interface Visitors {
-  /**
-   * A map from the node name to the Visitor
-   *
-   * During a DFS traversal of the AST tree if a directive node
-   * name matches the key in the directives map, the corresponding visitor is called
-   */
-  directives: { [name: string]: Visitor };
-}
-
-/**
- * Parse GraphQL schema
- * @constructor(schemaPath: string)
- */
-export class GraphQLSchemaParser {
-  // GraphQL shchema
-  schema: GraphQLSchema;
-  // List of the object types defined in schema
-  private _objectTypeDefinations: ObjectTypeDefinitionNode[];
-  private namedTypes: GraphQLNamedType[];
-
-  constructor(schemaPath: string) {
-    if (!fs.existsSync(schemaPath)) {
-      throw new Error('Schema not found');
-    }
-    const contents = fs.readFileSync(schemaPath, 'utf8');
-    this.schema = GraphQLSchemaParser.buildSchema(contents);
-    this.namedTypes = [
-      ...Object.values(this.schema.getTypeMap()).filter(
-        t => !t.name.startsWith('__') // filter out auxiliarry GraphQL types;
-      ),
-    ];
-    this._objectTypeDefinations = GraphQLSchemaParser.createObjectTypeDefinations(this.schema);
-  }
-
-  private static buildPreamble(): string {
-    let preamble = SCHEMA_DEFINITIONS_PREAMBLE;
-    DIRECTIVES.map(d => (preamble += d.preamble + '\n'));
-    return preamble;
-  }
-  /**
-   * Read GrapqhQL schema and build a schema from it
-   */
-  static buildSchema(contents: string): GraphQLSchema {
-    const schema = GraphQLSchemaParser.buildPreamble().concat(contents);
-    const ast = parse(schema);
-    // in order to build AST with undeclared directive, we need to
-    // switch off SDL validation
-    const schemaAST = buildASTSchema(ast);
-
-    const errors = validateSchema(schemaAST);
-
-    if (errors.length > 0) {
-      // There are errors
-      let errorMsg = `Schema is not valid. Please fix the following errors: \n`;
-      errors.forEach(e => (errorMsg += `\t ${e.name}: ${e.message}\n`));
-      debug(errorMsg);
-      throw new Error(errorMsg);
-    }
-
-    return schemaAST;
-  }
-
-  getEnumTypes(): GraphQLEnumType[] {
-    return [...this.namedTypes.filter(t => t instanceof GraphQLEnumType)] as GraphQLEnumType[];
-  }
-
-  getInterfaceTypes(): GraphQLInterfaceType[] {
-    return [...this.namedTypes.filter(t => t instanceof GraphQLInterfaceType)] as GraphQLInterfaceType[];
-  }
-
-  getUnionTypes(): GraphQLUnionType[] {
-    return [...this.namedTypes.filter(t => t instanceof GraphQLUnionType)] as GraphQLUnionType[];
-  }
-
-  /**
-   * Get object type definations from the schema. Build-in and scalar types are excluded.
-   */
-  static createObjectTypeDefinations(schema: GraphQLSchema): ObjectTypeDefinitionNode[] {
-    return [
-      ...Object.values(schema.getTypeMap())
-        // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
-        .filter(t => !t.name.match(/^__/) && !t.name.match(/Query/)) // skip the top-level Query type
-        .sort((a, b) => (a.name > b.name ? 1 : -1))
-        .map(t => t.astNode),
-    ]
-      .filter(Boolean) // Remove undefineds and nulls
-      .filter(typeDefinationNode => typeDefinationNode?.kind === 'ObjectTypeDefinition') as ObjectTypeDefinitionNode[];
-  }
-
-  /**
-   * Returns fields for a given GraphQL object
-   * @param objDefinationNode ObjectTypeDefinitionNode
-   */
-  getFields(objDefinationNode: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode): FieldDefinitionNode[] {
-    if (objDefinationNode.fields) return [...objDefinationNode.fields];
-    return [];
-  }
-
-  
-
-  /**
-   * Returns GraphQL object type definations
-   */
-  getObjectDefinations(): ObjectTypeDefinitionNode[] {
-    return this._objectTypeDefinations;
-  }
-
-  /**
-   * DFS traversal of the AST
-   */
-  dfsTraversal(visitors: Visitors): void {
-    // we traverse starting from each definition
-    this._objectTypeDefinations.map(objType => {
-      const path: SchemaNode[] = [];
-      visit(objType, {
-        enter: node => {
-          if (node.kind !== 'Directive' && node.kind !== 'ObjectTypeDefinition' && node.kind !== 'FieldDefinition') {
-            // skip non-definition fields;
-            return false;
-          }
-          path.push(node);
-          if (node.kind === 'Directive') {
-            if (node.name.value in visitors.directives) {
-              visitors.directives[node.name.value].visit(cloneDeep(path));
-            }
-          }
-        },
-        leave: () => path.pop(),
-      });
-    });
-  }
-}

+ 0 - 242
query-node/substrate-query-framework/cli/src/parse/WarthogModelBuilder.ts

@@ -1,242 +0,0 @@
-import {
-  ObjectTypeDefinitionNode,
-  FieldDefinitionNode,
-  ListTypeNode,
-  NamedTypeNode,
-  TypeDefinitionNode,
-  InterfaceTypeDefinitionNode,
-} from 'graphql';
-import { GraphQLSchemaParser, Visitors, SchemaNode } from './SchemaParser';
-import { WarthogModel, Field, ObjectType } from '../model';
-import Debug from 'debug';
-import { ENTITY_DIRECTIVE, UNIQUE_DIRECTIVE, VARIANT_DIRECTIVE } from './constant';
-import { FTSDirective, FULL_TEXT_SEARCHABLE_DIRECTIVE } from './FTSDirective';
-import { availableTypes } from '../model/ScalarTypes';
-import * as DerivedFrom from './DerivedFromDirective';
-import { RelationshipGenerator } from '../generate/RelationshipGenerator';
-
-const debug = Debug('qnode-cli:model-generator');
-
-/**
- * Parse a graphql schema and generate model defination strings for Warthog. It use GraphQLSchemaParser for parsing
- * @constructor(schemaPath: string)
- */
-export class WarthogModelBuilder {
-  private _schemaParser: GraphQLSchemaParser;
-  private _model: WarthogModel;
-  private _fieldsToProcess: Field[] = [];
-
-  constructor(schemaPath: string) {
-    this._schemaParser = new GraphQLSchemaParser(schemaPath);
-    this._model = new WarthogModel();
-  }
-
-  /**
-   * Returns true if type is Scalar, String, Int, Boolean, Float otherwise false
-   * Scalar types are also built-in
-   */
-  private _isBuildinType(type: string): boolean {
-    return type in availableTypes;
-  }
-
-  private _listType(typeNode: ListTypeNode, fieldName: string): Field {
-    let field: Field;
-
-    if (typeNode.type.kind === 'ListType') {
-      throw new Error('Only one level lists are allowed');
-    } else if (typeNode.type.kind === 'NamedType') {
-      field = this._namedType(fieldName, typeNode.type);
-      field.isList = true;
-    } else {
-      if (typeNode.type.type.kind === 'ListType') {
-        throw new Error('Only one level lists are allowed');
-      }
-      field = this._namedType(fieldName, typeNode.type.type);
-      field.nullable = false;
-    }
-
-    field.isList = true;
-    return field;
-  }
-
-  /**
-   * Create a new Field type from NamedTypeNode
-   * @param name string
-   * @param namedTypeNode NamedTypeNode
-   * @param directives: additional directives of FieldDefinitionNode
-   */
-  private _namedType(name: string, namedTypeNode: NamedTypeNode): Field {
-    const field = new Field(name, namedTypeNode.name.value);
-    field.isBuildinType = this._isBuildinType(field.type);
-
-    this._fieldsToProcess.push(field);
-
-    return field;
-  }
-
-  /**
-   * Mark the object type as entity if '@entity' directive is used
-   * @param o ObjectTypeDefinitionNode
-   */
-  private isEntity(o: TypeDefinitionNode): boolean {
-    const entityDirective = o.directives?.find(d => d.name.value === ENTITY_DIRECTIVE);
-    return entityDirective ? true : false;
-  }
-
-  private isVariant(o: TypeDefinitionNode): boolean {
-    if (o.directives == undefined) {
-      return false;
-    }
-
-    return o.directives.findIndex(d => d.name.value === VARIANT_DIRECTIVE) >= 0;
-  }
-
-  private isUnique(field: FieldDefinitionNode): boolean {
-    const entityDirective = field.directives?.find(d => d.name.value === UNIQUE_DIRECTIVE);
-    return entityDirective ? true : false;
-  }
-
-  /**
-   * Generate a new ObjectType from ObjectTypeDefinitionNode
-   * @param o ObjectTypeDefinitionNode
-   */
-  private generateTypeDefination(o: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode): ObjectType {
-    return {
-      name: o.name.value,
-      fields: this.getFields(o),
-      isEntity: this.isEntity(o),
-      isVariant: this.isVariant(o),
-      description: o.description?.value,
-      isInterface: o.kind === 'InterfaceTypeDefinition',
-      interfaces: o.kind === 'ObjectTypeDefinition' ? this.getInterfaces(o) : [],
-    } as ObjectType;
-  }
-
-  private getInterfaces(o: ObjectTypeDefinitionNode): ObjectType[] {
-    if (!o.interfaces) {
-      return [];
-    }
-    const interfaces: ObjectType[] = [];
-    o.interfaces.map(nameNode => {
-      if (nameNode.kind !== 'NamedType') {
-        throw new Error(`Unrecognized interface type: ${JSON.stringify(nameNode, null, 2)}`);
-      }
-      const name = nameNode.name.value;
-      interfaces.push(this._model.lookupInterface(name));
-    });
-
-    if (interfaces.length > 1) {
-      throw new Error(`A type can implement at most one interface`);
-    }
-    return interfaces;
-  }
-
-  private getFields(o: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode): Field[] {
-    const fields = this._schemaParser.getFields(o).map((fieldNode: FieldDefinitionNode) => {
-      const typeNode = fieldNode.type;
-      const fieldName = fieldNode.name.value;
-
-      let field: Field;
-
-      if (typeNode.kind === 'NamedType') {
-        field = this._namedType(fieldName, typeNode);
-      } else if (typeNode.kind === 'NonNullType') {
-        field =
-          typeNode.type.kind === 'NamedType'
-            ? this._namedType(fieldName, typeNode.type)
-            : this._listType(typeNode.type, fieldName);
-
-        field.nullable = false;
-      } else if (typeNode.kind === 'ListType') {
-        field = this._listType(typeNode, fieldName);
-      } else {
-        throw new Error(`Unrecognized type. ${JSON.stringify(typeNode, null, 2)}`);
-      }
-      field.description = fieldNode.description?.value;
-      field.unique = this.isUnique(fieldNode);
-      DerivedFrom.addDerivedFromIfy(fieldNode, field);
-      return field;
-    });
-    debug(`Read and parsed fields: ${JSON.stringify(fields, null, 2)}`);
-    return fields;
-  }
-
-  private generateInterfaces() {
-    this._schemaParser.getInterfaceTypes().map(i => {
-      const astNode = i.astNode as InterfaceTypeDefinitionNode;
-      if (astNode && this.isEntity(astNode)) {
-        this._model.addInterface(this.generateTypeDefination(astNode));
-      }
-    });
-  }
-
-  private generateEntities() {
-    this._schemaParser
-      .getObjectDefinations()
-      .filter(o => this.isEntity(o))
-      .map(o => {
-        const objType = this.generateTypeDefination(o);
-        this._model.addEntity(objType);
-      });
-  }
-
-  private generateVariants() {
-    this._schemaParser
-      .getObjectDefinations()
-      .filter(o => this.isVariant(o))
-      .map(o => {
-        const objType = this.generateTypeDefination(o);
-        this._model.addVariant(objType);
-      });
-  }
-
-  private generateUnions() {
-    this._schemaParser.getUnionTypes().map(u => {
-      const types: string[] = [];
-      u.getTypes().map(s => types.push(s.name));
-      this._model.addUnion(u.name, types);
-    });
-  }
-
-  private generateEnums() {
-    this._schemaParser.getEnumTypes().map(e => this._model.addEnum(e));
-  }
-
-  // TODO: queries will be parsed from a top-level directive definition
-  // and this part is going to be deprecated
-  private genereateQueries() {
-    const fts = new FTSDirective();
-    const visitors: Visitors = {
-      directives: {},
-    };
-    visitors.directives[FULL_TEXT_SEARCHABLE_DIRECTIVE] = {
-      visit: (path: SchemaNode[]) => fts.generate(path, this._model),
-    };
-    this._schemaParser.dfsTraversal(visitors);
-  }
-
-  private postProcessFields() {
-    while (this._fieldsToProcess) {
-      const f = this._fieldsToProcess.pop();
-      if (!f) return;
-      f.modelType = this._model.lookupType(f.type);
-    }
-  }
-
-  buildWarthogModel(): WarthogModel {
-    this._model = new WarthogModel();
-
-    this.generateEnums();
-    this.generateInterfaces();
-    this.generateVariants();
-    this.generateUnions();
-    this.generateEntities();
-    this.postProcessFields();
-    this.genereateQueries();
-
-    DerivedFrom.validateDerivedFields(this._model);
-    new RelationshipGenerator(this._model).generate();
-
-    return this._model;
-  }
-}

+ 0 - 22
query-node/substrate-query-framework/cli/src/parse/constant.ts

@@ -1,22 +0,0 @@
-/**
- * This preamble is added to the schema in order to pass the SDL validation
- * Add additional scalar types and directives to the schema
- */
-
-export const ENTITY_DIRECTIVE = 'entity';
-export const UNIQUE_DIRECTIVE = 'unique';
-export const VARIANT_DIRECTIVE = 'variant';
-export const DERIVED_FROM_DIRECTIVE = `derivedFrom`;
-
-export const SCHEMA_DEFINITIONS_PREAMBLE = `
-directive @${VARIANT_DIRECTIVE} on OBJECT # varaint types
-directive @${ENTITY_DIRECTIVE} on OBJECT | INTERFACE  # Mark both object types and interfaces
-directive @${DERIVED_FROM_DIRECTIVE}(field: String!) on FIELD_DEFINITION
-directive @${UNIQUE_DIRECTIVE} on FIELD_DEFINITION
-scalar BigInt                # Arbitrarily large integers
-scalar BigDecimal            # is used to represent arbitrary precision decimals
-scalar Bytes                 # Byte array, represented as a hexadecimal string
-type Query {
-    _dummy: String           # empty queries are not allowed
-}
-`;

+ 0 - 14
query-node/substrate-query-framework/cli/src/templates/db-helper.mst

@@ -1,14 +0,0 @@
-import { getConnection } from "typeorm";
-import * as shortid from "shortid";
-
-/**
- * Fixes compatibility between typeorm and warthog by filling id, createById and version
- * @param entity Instance of the entity
- */
-export function insertToDatabase<T>(entity: T) {
-  entity["id"] = shortid.generate();
-  entity["createdById"] = shortid.generate();
-  entity["version"] = 1;
-
-  getConnection().getRepository(entity.constructor.name).insert(entity);
-}

+ 0 - 9
query-node/substrate-query-framework/cli/src/templates/dotenv-ormconfig.mst

@@ -1,9 +0,0 @@
-TYPEORM_CONNECTION=postgres
-TYPEORM_HOST=localhost
-TYPEORM_USERNAME=postgres
-TYPEORM_PASSWORD=postgres
-TYPEORM_DATABASE=postgres
-TYPEORM_PORT=5432
-TYPEORM_SYNCHRONIZE=false
-TYPEORM_LOGGING=true
-TYPEORM_ENTITIES=node_modules/index-builder/lib/db/entities.js,../graphql-server/src/modules/**/*.model.ts

+ 0 - 1
query-node/substrate-query-framework/cli/src/templates/dotenv.mst

@@ -1 +0,0 @@
-WS_PROVIDER_ENDPOINT_URI=ws://localhost:9944

+ 0 - 7
query-node/substrate-query-framework/cli/src/templates/entities/enums.ts.mst

@@ -1,7 +0,0 @@
-{{#enums}}
-  export enum {{name}} {
-  {{#values}}  
-    {{name}} = '{{value}}',
-  {{/values}}
-  }
-{{/enums}}

+ 0 - 138
query-node/substrate-query-framework/cli/src/templates/entities/model.ts.mst

@@ -1,138 +0,0 @@
-import {
-  BaseModel,
-  {{#has.bool}}BooleanField,{{/has.bool}}
-  {{#has.date}}DateField,{{/has.date}}
-  {{#has.float}}FloatField,{{/has.float}}
-  {{#has.int}}IntField,{{/has.int}}
-  {{#has.numeric}}NumericField,{{/has.numeric}}
-  {{#has.json}}JSONField,{{/has.json}}
-  {{#has.bytes}}BytesField,{{/has.bytes}}
-  Model,
-  {{#has.mto}}ManyToOne,{{/has.mto}}
-  {{#has.mtm}}ManyToMany,{{/has.mtm}}
-  {{#has.otm}}OneToMany,{{/has.otm}}
-  {{#has.oto}}OneToOne, OneToOneJoin,{{/has.oto}}
-  {{#has.array}}CustomField,{{/has.array}}
-  {{#has.enum}}EnumField,{{/has.enum}}
-  StringField
-} from 'warthog';  {{! we don't need extra twists here }}
-
-{{#has.numeric}}import * as BN from 'bn.js' {{/has.numeric}}
-
-{{#has.union}}
-import { Column } from 'typeorm';
-import { Field } from 'type-graphql';
-import { WarthogField } from 'warthog';
-{{#fields}}
-  {{#is.union}}
-  import { {{tsType}} } from '../variants/variants.model';
-  {{/is.union}}
-{{/fields}}
-{{/has.union}}
-
-{{#isInterface}}
-import { InterfaceType } from 'type-graphql';
-{{/isInterface}}
-
-{{#has.mtm}}import { JoinTable } from 'typeorm';{{/has.mtm}}
-
-{{#relatedEntityImports}}
-  {{{ . }}}
-{{/relatedEntityImports}}
-
-{{#enums}}
-  import { {{name}} } from '../enums/enums';
-  {{#export}}
-  export { {{name}} }; {{! we need to re-export enums for type-GraphQL to resolve types correctly, but only once }}
-  {{/export}}
-{{/enums}}
-
-{{#interfaces}}
-  import { {{className}} } from '../{{kebabName}}/{{kebabName}}.model';
-{{/interfaces}}
-
-{{^isInterface}}
-@Model({ api: { {{#interfaces}}implements: {{className}},{{/interfaces}} {{#description}} description: `{{{description}}}`{{/description}} }}) {{! only a single interface can be here }}
-{{/isInterface}}
-{{#isInterface}}
-@InterfaceType({{#description}} { description: `{{{description}}}` } {{/description}})
-{{/isInterface}}
-export {{#isInterface}}abstract{{/isInterface}} class {{className}} 
-  extends {{^interfaces}}BaseModel{{/interfaces}} {{#interfaces}} {{className}} {{/interfaces}} {
-
-{{#fields}}
-  {{#is.otm}}
-    @OneToMany(() => {{relation.columnType}}, (param: {{relation.columnType}}) => param.{{relation.relatedTsProp}})
-    {{camelName}}?: {{relation.columnType}}[];  
-  {{/is.otm}}
-
-  {{#is.mto}}
-    @ManyToOne(() => {{relation.columnType}},
-      {{#relation.relatedTsProp}}
-        (param: {{relation.columnType}}) => param.{{relation.relatedTsProp}},
-      {{/relation.relatedTsProp}}
-      { 
-        skipGraphQLField: true{{^required}},
-        nullable: true{{/required}} 
-    })
-    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{relation.columnType}};
-  {{/is.mto}}
-
-  {{#is.oto}}
-    {{^relation.joinColumn}}@OneToOne{{/relation.joinColumn}}
-    {{#relation.joinColumn}}@OneToOneJoin{{/relation.joinColumn}}
-    (() => {{relation.columnType}},(param: {{relation.columnType}}) => param.{{relation.relatedTsProp}})
-    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{relation.columnType}};
-  {{/is.oto}}
-
-  {{#is.mtm}}
-    @ManyToMany(() => {{relation.columnType}}, (param: {{relation.columnType}}) => param.{{relation.relatedTsProp}})
-    {{#relation.joinTable}}
-      @JoinTable({
-        name: '{{relation.joinTable.tableName}}',
-        joinColumn: {name: '{{relation.joinTable.joinColumn}}' },
-        inverseJoinColumn: {name: '{{relation.joinTable.inverseJoinColumn}}' }
-      })
-    {{/relation.joinTable}}
-    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{relation.columnType}}[];
-  {{/is.mtm}}
-  
-  {{#is.array}}
-    @CustomField({
-      db: { type: '{{dbType}}', array: true,{{^required}}nullable: true,{{/required}} {{#unique}}unique: true,{{/unique}}}, 
-      api: { type: '{{apiType}}', {{^required}}nullable: true,{{/required}}
-        {{#description}}description: `{{{description}}}`{{/description}} }
-    })
-    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{tsType}}[];
-  {{/is.array}}
-
-  {{! TODO: add enums here }}
-  {{#is.scalar}}
-    @{{decorator}}({
-      {{^required}}nullable: true,{{/required}}
-      {{#description}}description: `{{{description}}}`,{{/description}}
-      {{#unique}}unique: true,{{/unique}}
-      {{#transformer}} transformer: {{{transformer}}}, {{/transformer}}
-    })
-    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: {{tsType}};
-  {{/is.scalar}}
-
-  {{#is.enum}}
-    @EnumField('{{tsType}}', {{tsType}}, { 
-      {{^required}}nullable: true,{{/required}} 
-      {{#description}}description: `{{{description}}}`{{/description}} })
-    {{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}:{{tsType}} 
-  {{/is.enum}}
-
-
-  {{#is.union}} 
-	@Column('jsonb')
-	@WarthogField('json')
-	@Field(type => {{tsType}}, {
-      {{^required}}nullable: true,{{/required}} 
-      {{#description}}description: `{{{description}}}`{{/description}} })
-	{{camelName}}{{^required}}?{{/required}}{{#required}}!{{/required}}: typeof {{tsType}}
-  {{/is.union}}
-
-{{/fields}}
-}

+ 0 - 43
query-node/substrate-query-framework/cli/src/templates/entities/resolver.ts.mst

@@ -1,43 +0,0 @@
-import { Arg, Args, Mutation, Query, Resolver, Root, FieldResolver} from 'type-graphql';
-import { Inject } from 'typedi';
-import { Fields, StandardDeleteResponse, UserId } from 'warthog';
-
-import {
-  {{className}}CreateInput,
-  {{className}}CreateManyArgs,
-  {{className}}UpdateArgs,
-  {{className}}WhereArgs,
-  {{className}}WhereInput,
-  {{className}}WhereUniqueInput
-} from '{{{generatedFolderRelPath}}}';
-
-import { {{className}} } from './{{kebabName}}.model';
-import { {{className}}Service } from './{{kebabName}}.service';
-
-{{#fieldResolverImports}}
-  {{{.}}}
-{{/fieldResolverImports}}
-
-@Resolver({{className}})
-export class {{className}}Resolver {
-  constructor(@Inject('{{className}}Service') public readonly service: {{className}}Service) {}
-
-  @Query(() => [{{className}}])
-  async {{camelNamePlural}}(
-    @Args() { where, orderBy, limit, offset }: {{className}}WhereArgs,
-    @Fields() fields: string[]
-  ): Promise<{{className}}[]> {
-    return this.service.find<{{className}}WhereInput>(where, orderBy, limit, offset, fields);
-  }
-
-  {{#fieldResolvers}}
-    @FieldResolver(() => {{returnTypeFunc}})
-    async {{fieldName}}(@Root() {{rootArgName}}: {{rootArgType}}): {{{returnType}}} {
-      const result = await getConnection().getRepository({{rootArgType}}).findOne({{rootArgName}}.id, { relations: ['{{fieldName}}'] })
-      if (!result || !result.{{fieldName}}) {
-        throw new Error('Unable to find result for {{rootArgType}}.{{fieldName}}');
-      }
-      return result.{{fieldName}};
-    }
-  {{/fieldResolvers}}
-}

+ 0 - 39
query-node/substrate-query-framework/cli/src/templates/entities/service.ts.mst

@@ -1,39 +0,0 @@
-import { Service } from 'typedi';
-import { Repository } from 'typeorm';
-import { InjectRepository } from 'typeorm-typedi-extensions';
-import { BaseService, WhereInput } from 'warthog';
-
-import { {{className}} } from './{{kebabName}}.model';
-
-@Service('{{className}}Service')
-export class {{className}}Service extends BaseService<{{className}}> {
-  constructor(
-    @InjectRepository({{className}}) protected readonly repository: Repository<{{className}}>
-  ) {
-    super({{className}}, repository);
-  }
-
-
-  async find<W extends WhereInput>(
-		where?: any,
-		orderBy?: string,
-		limit?: number,
-		offset?: number,
-		fields?: string[]
-	): Promise<{{className}}[]> {
-		let f = fields;
-		if (f == undefined) {
-			f = [];
-		}
-    {{#fields}}
-      {{#is.union}}
-        if (!f.includes('{{camelName}}')) {
-          f = [...f, '{{camelName}}'];
-        }
-      {{/is.union}}
-    {{/fields}}
-
-		return super.find<W>(where, orderBy, limit, offset, f);
-	}
-
-}

+ 0 - 5
query-node/substrate-query-framework/cli/src/templates/event-class-defination.mst

@@ -1,5 +0,0 @@
-export default class {{input.name}} {
-  {{#input.fields}}
-    {{name}}: {{type}}
-  {{/input.fields}}
-}

+ 0 - 42
query-node/substrate-query-framework/cli/src/templates/graphql-server.index.mst

@@ -1,42 +0,0 @@
-import 'reflect-metadata';
-
-import { SnakeNamingStrategy } from 'warthog';
-import { snakeCase } from 'typeorm/util/StringUtils';
-
-import { loadConfig } from '../src/config';
-import { Logger } from '../src/logger';
-
-import { getServer } from './server';
-
-class CustomNamingStrategy extends SnakeNamingStrategy {
-  constructor() {
-    super();
-  }
-  tableName(className: string, customName?: string): string {
-    return customName ? customName : `${snakeCase(className)}`;
-  }
-}
-
-async function bootstrap() {
-  await loadConfig();
-
-  const server = getServer({}, { namingStrategy: new CustomNamingStrategy() });
-
-  // Create database tables. Warthog migrate command does not support CustomNamingStrategy thats why
-  // we have this code
-  const syncDatabase: string | undefined = process.env.SYNC;
-  if (syncDatabase === 'true') {
-    await server.establishDBConnection();
-    process.exit(0);
-  }
-
-  await server.start();
-}
-
-bootstrap().catch((error: Error) => {
-  Logger.error(error);
-  if (error.stack) {
-    Logger.error(error.stack.split('\n'));
-  }
-  process.exit(1);
-});

+ 0 - 185
query-node/substrate-query-framework/cli/src/templates/index-builder-entry.mst

@@ -1,185 +0,0 @@
-import "reflect-metadata";
-import * as dotenv from "dotenv";
-import * as chalk from "chalk";
-import * as figlet from "figlet";
-import * as commander from "commander";
-import { configure, getLogger } from "log4js";
-
-{{#typeRegistrator}}
-import { {{typeRegistrator}} } from '{{{packageName}}}';
-{{/typeRegistrator}}
-
-import {
-  QueryNodeManager,
-  BootstrapPack,
-  BootstrapFunc,
-  DatabaseManager,
-  SubstrateEvent,
-  createDBConnection,
-  SavedEntityEvent
-} from '@dzlzv/hydra-indexer-lib/lib';
-
-// Mappings use!
-export { DatabaseManager as DB, getLogger, SubstrateEvent };
-
-const logger = getLogger();
-
-function getProcessingPack() {
-  const handlers = require("../../mappings");
-
-  let processingPack: { [key: string]: any } = {};
-
-  Object.keys(handlers)
-    .filter((handler) => handler.startsWith("handle"))
-    .map((handler: string) => {
-      let eventName = handler.replace("handle", "");
-      processingPack[eventName] = handlers[handler];
-    });
-  return processingPack;
-}
-
-function getBootstrapPack() {
-  const bootstrapPack: BootstrapPack = { pack: [] };
-  if (!process.env.BOOTSTRAP_PACK_LOCATION) {
-    // TODO: very basic, we should read form the config file
-    throw new Error(`No boostrap location found. 
-Please set BOOTSTRAP_FILE_LOCATION environment variable`);
-  }
-  let handlers: { [key: string]: BootstrapFunc } = {};
-  try {
-    handlers = require(process.env.BOOTSTRAP_PACK_LOCATION);
-  } catch (e) {
-    throw new Error(
-      `Cannot load bootstrap mappings from ${process.env.BOOTSTRAP_FILE_LOCATION}: ${e}`
-    );
-  }
-
-  Object.keys(handlers)
-    .filter((handler) => handler.startsWith("boot"))
-    .map((handler: string) => bootstrapPack.pack.push(handlers[handler]));
-
-  return bootstrapPack;
-}
-
-const withErrors = (command: (...args: any[]) => Promise<void>) => {
-  return async (...args: any[])=> {
-    try {
-      await command(...args)
-    } catch(e) {
-      console.log(chalk.red(e.stack));
-      process.exit(1);
-    }
-  }
-}
-
-const withEnvs = (command: () => Promise<void>) => {
-  return async (opts: any) => {
-    setUp(opts);
-    await command();
-  }
-}
-
-
-function main(): commander.Command {
-  console.log(chalk.green(figlet.textSync("{{projectName}}-Indexer")));
-  const program = new commander.Command();
-  const version = require("./package.json").version;
-
-  program
-    .version(version)
-    .description("{{projectName}} Indexer");
-
-  program
-    .command('bootstrap')
-    .description('Bootstrap the model with boot* handlers')
-    .action(withErrors(withEnvs(runBootstrap)));  
-
-  program
-    .command('index')
-    .option('-h, --height', 'starting block height')
-    .option('-e, --env <file>', '.env file location', '../../.env')
-    .description('Index all events and extrinsics in the substrate chain')
-    .action(withErrors(withEnvs(runIndexer)));
-
-  program
-    .command('process')
-    .option('-h, --height', 'starting block height')
-    .option('-e, --env <file>', '.env file location', '../../.env')
-    .description('Process the event and extrinsic mappings using the index')
-    .action(withErrors(withEnvs(runProcessor)));
-
-  program
-    .command('migrate')
-    .description('Create the indexer schema')
-    .option('-e, --env <file>', '.env file location', '../../.env')
-    .action(withErrors(withEnvs(runMigrations)));
-    
-  program.parse(process.argv);
-
-  return program;
-}
-
-function setUp(opts: any) {
-  if (opts.bootstrap) {
-    process.env.QUERY_NODE_BOOTSTRAP_DB = "true";
-  }
-
-  // dotenv config
-  dotenv.config(); 
-  dotenv.config({ path: opts.env });
-
-  if (opts.height) {
-    process.env.BLOCK_HEIGHT = opts.height;
-  } else if (!process.env.BLOCK_HEIGHT) {
-    process.env.BLOCK_HEIGHT = '0';
-  }
-
-  //log4js config
-  if (opts.logging) {
-    configure(opts.logging);
-  } else {
-    // log4js default: DEBUG to console output;
-    getLogger().level = 'debug';
-  }
-}
-
-async function runBootstrap() {
-  const node = new QueryNodeManager();
-  await node.bootstrap({
-    wsProviderURI: process.env.WS_PROVIDER_ENDPOINT_URI || '',
-    processingPack: getBootstrapPack(),
-    {{#typeRegistrator}}typeRegistrator: {{typeRegistrator}} {{/typeRegistrator}}
-  });
-
-  logger.info("Bootstrap done");
-}
-
-async function runProcessor() {
-  const node = new QueryNodeManager();
-  const atBlock = process.env.BLOCK_HEIGHT;
-  await node.process({
-    atBlock: atBlock && atBlock !== '0' ? Number.parseInt(atBlock) : undefined,
-    processingPack: getProcessingPack(),
-  });
-}
-
-async function runIndexer() {
-  const node = new QueryNodeManager();
-  const atBlock = process.env.BLOCK_HEIGHT;
-  await node.index({
-    wsProviderURI: process.env.WS_PROVIDER_ENDPOINT_URI || '',
-    atBlock: atBlock && atBlock !== '0' ? Number.parseInt(atBlock) : undefined,
-    {{#typeRegistrator}}typeRegistrator: {{typeRegistrator}} {{/typeRegistrator}}
-  });
-}
-
-async function runMigrations() {
-  logger.info(`Running migrations`);
-  await new QueryNodeManager().migrate();
-  // TODO: here should be TypeORM migrations...
-}
-
-
-main();
-
-

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません