@powerhousedao/analytics-engine-graphql 6.1.0-dev.2 → 6.1.0-dev.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/AnalyticsResolvers.ts","../src/AnalyticsModel.ts","../src/schema.ts"],"mappings":";;;;cAEa,kBAAA;;;KCMD,WAAA;EACV,KAAA;EACA,GAAA;EACA,WAAA;EACA,OAAA;EACA,UAAA,GAAa,MAAA;EACb,QAAA;AAAA;AAAA,KAGG,kBAAA;EACH,MAAA;EACA,cAAA;AAAA;AAAA,KAGG,mBAAA,GAAsB,WAAA;EACzB,WAAA,EAAa,kBAAA;AAAA;AAAA,cAGF,cAAA;EAAA,SAIO,MAAA,EAAQ,oBAAA;EAH1B,WAAA,GAAc,KAAA,EAAO,cAAA;cAGH,MAAA,EAAQ,oBAAA,EACxB,WAAA,IAAe,KAAA,EAAO,cAAA;EAKX,KAAA,CAAM,MAAA,EAAQ,WAAA,GAAW,OAAA;;;;;;;;;;;;EAmDzB,kBAAA,CAAmB,MAAA,EAAQ,mBAAA,GAAmB,OAAA,CAAA,qCAAA,CAAA,oBAAA;EA+C9C,aAAA,CAAA,GAAa,OAAA;EAIb,aAAA,CAAA,GAAa,OAAA;AAAA;;;cC1If,QAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/AnalyticsResolvers.ts","../src/AnalyticsModel.ts","../src/schema.ts"],"mappings":";;;;cAEa,kBAAA;;;KCMD,WAAA;EACV,KAAA;EACA,GAAA;EACA,WAAA;EACA,OAAA;EACA,UAAA,GAAa,MAAA;EACb,QAAA;AAAA;AAAA,KAGG,kBAAA;EACH,MAAA;EACA,cAAA;AAAA;AAAA,KAGG,mBAAA,GAAsB,WAAA;EACzB,WAAA,EAAa,kBAAA;AAAA;AAAA,cAGF,cAAA;EAAA,SAIO,MAAA,EAAQ,oBAAA;EAH1B,WAAA,GAAc,KAAA,EAAO,cAAA;cAGH,MAAA,EAAQ,oBAAA,EACxB,WAAA,IAAe,KAAA,EAAO,cAAA;EAKX,KAAA,CAAM,MAAA,EAAQ,WAAA,GAAW,OAAA;;;;;;;;;;;;EAmDzB,kBAAA,CAAmB,MAAA,EAAQ,mBAAA,GAAmB,OAAA,CAAA,qCAAA,CAAA,oBAAA;EA+C9C,aAAA,CAAA,GAAa,OAAA;EAInB,aAAA,CAAA,GAAiB,OAAA;AAAA;;;cC1Ib,QAAA"}
package/dist/index.js CHANGED
@@ -2,11 +2,11 @@ import { AnalyticsGranularity, AnalyticsPath } from "@powerhousedao/analytics-en
2
2
  import { DateTime } from "luxon";
3
3
  //#region src/AnalyticsResolvers.ts
4
4
  const AnalyticsResolvers = {
5
- Query: { analytics: (_, __, { dataSources }) => {
5
+ Query: { analytics: (_, __, { dataSources: _dataSources }) => {
6
6
  return {};
7
7
  } },
8
8
  AnalyticsQuery: {
9
- series: async (parent, { filter }, { dataSources }) => {
9
+ series: async (_parent, { filter }, { dataSources }) => {
10
10
  return (await dataSources.db.Analytics.query(filter)).map((s) => ({
11
11
  ...s,
12
12
  rows: s.rows.map((r) => ({
@@ -21,8 +21,8 @@ const AnalyticsResolvers = {
21
21
  }))
22
22
  }));
23
23
  },
24
- metrics: async (parent, { filter }, { dataSources }) => {
25
- return [
24
+ metrics: (_parent, { filter: _filter }, { dataSources: _dataSources }) => {
25
+ return Promise.resolve([
26
26
  "Actuals",
27
27
  "AuditorNetOutflow",
28
28
  "Budget",
@@ -37,13 +37,13 @@ const AnalyticsResolvers = {
37
37
  "PaymentsOffChainIncluded",
38
38
  "PaymentsOnChain",
39
39
  "ProtocolNetOutflow"
40
- ];
40
+ ]);
41
41
  },
42
- dimensions: async (_, { filter }, { dataSources }) => {
42
+ dimensions: async (_, { filter: _filter }, { dataSources }) => {
43
43
  return await dataSources.db.Analytics.getDimensions();
44
44
  },
45
- currencies: async (_, { filter }, { dataSources }) => {
46
- return [
45
+ currencies: (_, { filter: _filter }, { dataSources: _dataSources }) => {
46
+ return Promise.resolve([
47
47
  "DAI",
48
48
  "FTE",
49
49
  "GUSD",
@@ -51,7 +51,7 @@ const AnalyticsResolvers = {
51
51
  "USDC",
52
52
  "USDP",
53
53
  "USDT"
54
- ];
54
+ ]);
55
55
  },
56
56
  multiCurrencySeries: async (_, { filter }, { dataSources }) => {
57
57
  return (await dataSources.db.Analytics.multiCurrencyQuery(filter)).map((s) => ({
@@ -135,15 +135,15 @@ var AnalyticsModel = class {
135
135
  async getDimensions() {
136
136
  return await this.engine.getDimensions();
137
137
  }
138
- async getCurrencies() {
139
- return [
138
+ getCurrencies() {
139
+ return Promise.resolve([
140
140
  "DAI",
141
141
  "FTE",
142
142
  "MKR",
143
143
  "USDC",
144
144
  "USDP",
145
145
  "USDT"
146
- ];
146
+ ]);
147
147
  }
148
148
  };
149
149
  const getGranularity = (granularity) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/AnalyticsResolvers.ts","../src/AnalyticsModel.ts","../src/schema.ts"],"sourcesContent":["import type { AnalyticsModel } from \"./AnalyticsModel.js\";\n\nexport const AnalyticsResolvers: any = {\n Query: {\n analytics: (_: any, __: any, { dataSources }: any) => {\n return {};\n },\n },\n AnalyticsQuery: {\n series: async (parent: any, { filter }: any, { dataSources }: any) => {\n const queryEngine: AnalyticsModel = dataSources.db.Analytics;\n const results = await queryEngine.query(filter);\n return results.map((s) => ({\n ...s,\n rows: s.rows.map((r: any) => ({\n ...r,\n dimensions: Object.keys(r.dimensions).map((d) => ({\n name: d,\n path: r.dimensions[d][\"path\"],\n icon: r.dimensions[d][\"icon\"],\n label: r.dimensions[d][\"label\"],\n description: r.dimensions[d][\"description\"],\n })),\n })),\n }));\n },\n metrics: async (parent: any, { filter }: any, { dataSources }: any) => {\n return [\n \"Actuals\",\n \"AuditorNetOutflow\",\n \"Budget\",\n \"Contributors\",\n \"Count\",\n \"DailyDaiPriceChange\",\n \"DailyEthPriceChange\",\n \"DailyMkrPriceChange\",\n \"DailyUsdcPriceChange\",\n \"DailyUsdpPriceChange\",\n \"Forecast\",\n \"PaymentsOffChainIncluded\",\n \"PaymentsOnChain\",\n \"ProtocolNetOutflow\",\n ];\n },\n dimensions: async (_: any, { filter }: any, { dataSources }: any) => {\n const queryEngine: AnalyticsModel = dataSources.db.Analytics;\n return await queryEngine.getDimensions();\n },\n currencies: async (_: any, { filter }: any, { dataSources }: any) => {\n return [\"DAI\", \"FTE\", \"GUSD\", \"MKR\", \"USDC\", \"USDP\", \"USDT\"];\n },\n multiCurrencySeries: async (\n _: any,\n { filter }: any,\n { dataSources }: any,\n ) => {\n const queryEngine: AnalyticsModel = dataSources.db.Analytics;\n const results = await queryEngine.multiCurrencyQuery(filter);\n\n return results.map((s) => ({\n ...s,\n rows: s.rows.map((r: any) => ({\n ...r,\n dimensions: Object.keys(r.dimensions).map((d) => ({\n name: d,\n path: r.dimensions[d][\"path\"],\n icon: r.dimensions[d][\"icon\"],\n label: r.dimensions[d][\"label\"],\n description: r.dimensions[d][\"description\"],\n })),\n })),\n }));\n },\n },\n};\n","import type { AnalyticsQueryEngine } from \"@powerhousedao/analytics-engine-core\";\nimport {\n AnalyticsGranularity,\n AnalyticsPath,\n type AnalyticsQuery,\n} from \"@powerhousedao/analytics-engine-core\";\nimport { DateTime } from \"luxon\";\n\nexport type queryFilter = {\n start?: string;\n end?: string;\n granularity?: string;\n metrics: string[];\n dimensions: [Record<string, string>];\n currency?: string;\n};\n\ntype CurrencyConversion = {\n metric: string;\n sourceCurrency: string;\n};\n\ntype MultiCurrencyFilter = queryFilter & {\n conversions: CurrencyConversion[];\n};\n\nexport class AnalyticsModel {\n queryLogger: (query: AnalyticsQuery) => void;\n\n constructor(\n public readonly engine: AnalyticsQueryEngine,\n queryLogger?: (query: AnalyticsQuery) => void,\n ) {\n this.queryLogger = queryLogger || (() => {});\n }\n\n public async query(filter: queryFilter) {\n if (!filter) {\n return [];\n }\n\n const query: AnalyticsQuery = {\n start: filter.start ? DateTime.fromISO(filter.start) : null,\n end: filter.end ? DateTime.fromISO(filter.end) : null,\n granularity: getGranularity(filter.granularity),\n metrics: filter.metrics,\n currency: getCurrency(filter.currency),\n select: {},\n lod: {},\n };\n\n if (query.start && !query.start.isValid) {\n query.start = null;\n }\n\n if (query.end && !query.end.isValid) {\n query.end = null;\n }\n\n if (filter.dimensions.length < 1) {\n throw new Error(\"No dimensions provided\");\n } else {\n filter.dimensions.forEach((dimension) => {\n query.select[dimension.name] = [\n AnalyticsPath.fromString(dimension.select),\n ];\n query.lod[dimension.name] = Number(dimension.lod);\n });\n }\n\n this.queryLogger(query);\n\n const results = await this.engine.execute(query);\n\n // convert dates again\n const convertedResults = results.map((r) => ({\n ...r,\n start: r.start.toJSDate(),\n end: r.end.toJSDate(),\n }));\n\n return convertedResults;\n\n // TODO: pull caching interface out into analytics module\n //return measureAnalyticsQueryPerformance('analyticsQuery', 'analyticsQuery', query, false, \"high\");\n }\n\n public async multiCurrencyQuery(filter: MultiCurrencyFilter) {\n if (!filter) {\n return [];\n }\n\n const query: AnalyticsQuery = {\n start: filter.start ? DateTime.fromISO(filter.start) : null,\n end: filter.end ? DateTime.fromISO(filter.end) : null,\n granularity: getGranularity(filter.granularity),\n metrics: filter.metrics,\n currency: getCurrency(filter.currency),\n select: {},\n lod: {},\n };\n\n if (query.start && !query.start.isValid) {\n query.start = null;\n }\n\n if (query.end && !query.end.isValid) {\n query.end = null;\n }\n\n if (filter.dimensions.length < 1) {\n throw new Error(\"No dimensions provided\");\n } else {\n filter.dimensions.forEach((dimension) => {\n query.select[dimension.name] = [\n AnalyticsPath.fromString(dimension.select),\n ];\n query.lod[dimension.name] = Number(dimension.lod);\n });\n }\n\n this.queryLogger(query);\n\n return this.engine.executeMultiCurrency(query, {\n targetCurrency: query.currency,\n conversions: filter.conversions.map((c) => {\n return {\n metric: c.metric,\n currency: getCurrency(c.sourceCurrency),\n };\n }),\n });\n }\n\n public async getDimensions() {\n return await this.engine.getDimensions();\n }\n\n public async getCurrencies() {\n // todo: use knex inside of the analytics engine to select distinct currencies\n return [\"DAI\", \"FTE\", \"MKR\", \"USDC\", \"USDP\", \"USDT\"];\n }\n}\n\nconst getGranularity = (\n granularity: string | undefined,\n): AnalyticsGranularity => {\n switch (granularity) {\n case \"hourly\": {\n return AnalyticsGranularity.Hourly;\n }\n case \"daily\": {\n return AnalyticsGranularity.Daily;\n }\n case \"weekly\": {\n return AnalyticsGranularity.Weekly;\n }\n case \"monthly\": {\n return AnalyticsGranularity.Monthly;\n }\n case \"quarterly\": {\n return AnalyticsGranularity.Quarterly;\n }\n case \"semiAnnual\": {\n return AnalyticsGranularity.SemiAnnual;\n }\n case \"annual\": {\n return AnalyticsGranularity.Annual;\n }\n case \"total\": {\n return AnalyticsGranularity.Total;\n }\n default: {\n return AnalyticsGranularity.Total;\n }\n }\n};\n\nconst getCurrency = (currency: string | undefined) => {\n return currency ? AnalyticsPath.fromString(currency) : undefined;\n};\n","export const typedefs = `\ntype AnalyticsQuery {\n series(filter: AnalyticsFilter): [AnalyticsPeriod]\n multiCurrencySeries(filter: MultiCurrencyConversions): [AnalyticsPeriod]\n metrics: [String]\n dimensions: [Dimension]\n currencies: [String]\n}\n\ntype AnalyticsPeriod {\n period: String\n start: DateTime\n end: DateTime\n rows: [AnalyticsSeries]\n}\n\ntype AnalyticsSeries {\n dimensions: [AnalyticsSeriesDimension]\n metric: String\n unit: String\n value: Float\n sum: Float\n}\n\ntype AnalyticsSeriesDimension {\n name: String\n path: String\n label: String\n description: String\n icon: String\n}\n\ntype Dimension {\n name: String\n values: [Value]\n}\n\ntype Value {\n path: String\n label: String\n description: String\n icon: String\n}\n\nenum AnalyticsGranularity {\n hourly\n daily\n weekly\n monthly\n quarterly\n semiAnnual\n annual\n total\n}\n\ninput AnalyticsFilterDimension {\n name: String!\n select: String!\n lod: Int!\n}\n\ninput MultiCurrencyConversions {\n start: String\n end: String\n \"Period to group by\"\n granularity: AnalyticsGranularity\n \"List of metrics to filter by, such as 'budget' or 'actuals'\"\n metrics: [String]\n \"List of dimensions to filter by, such as 'budget' or 'project'\"\n dimensions: [AnalyticsFilterDimension]\n currency: String\n conversions: [CurrencyConversion]!\n}\n\ninput CurrencyConversion {\n metric: String!\n sourceCurrency: String!\n}\n\ninput AnalyticsFilter {\n start: String\n end: String\n \"Period to group by\"\n granularity: AnalyticsGranularity\n \"List of metrics to filter by, such as 'budget' or 'actuals'\"\n metrics: [String]\n \"List of dimensions to filter by, such as 'budget' or 'project'\"\n dimensions: [AnalyticsFilterDimension]\n currency: String\n}\n\nextend type Query {\n analytics: AnalyticsQuery\n}\n`;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/AnalyticsResolvers.ts","../src/AnalyticsModel.ts","../src/schema.ts"],"sourcesContent":["import type { AnalyticsModel } from \"./AnalyticsModel.js\";\n\nexport const AnalyticsResolvers: any = {\n Query: {\n analytics: (_: any, __: any, { dataSources: _dataSources }: any) => {\n return {};\n },\n },\n AnalyticsQuery: {\n series: async (_parent: any, { filter }: any, { dataSources }: any) => {\n const queryEngine: AnalyticsModel = dataSources.db.Analytics;\n const results = await queryEngine.query(filter);\n return results.map((s) => ({\n ...s,\n rows: s.rows.map((r: any) => ({\n ...r,\n dimensions: Object.keys(r.dimensions).map((d) => ({\n name: d,\n path: r.dimensions[d][\"path\"],\n icon: r.dimensions[d][\"icon\"],\n label: r.dimensions[d][\"label\"],\n description: r.dimensions[d][\"description\"],\n })),\n })),\n }));\n },\n metrics: (\n _parent: any,\n { filter: _filter }: any,\n { dataSources: _dataSources }: any,\n ) => {\n return Promise.resolve([\n \"Actuals\",\n \"AuditorNetOutflow\",\n \"Budget\",\n \"Contributors\",\n \"Count\",\n \"DailyDaiPriceChange\",\n \"DailyEthPriceChange\",\n \"DailyMkrPriceChange\",\n \"DailyUsdcPriceChange\",\n \"DailyUsdpPriceChange\",\n \"Forecast\",\n \"PaymentsOffChainIncluded\",\n \"PaymentsOnChain\",\n \"ProtocolNetOutflow\",\n ]);\n },\n dimensions: async (\n _: any,\n { filter: _filter }: any,\n { dataSources }: any,\n ) => {\n const queryEngine: AnalyticsModel = dataSources.db.Analytics;\n return await queryEngine.getDimensions();\n },\n currencies: (\n _: any,\n { filter: _filter }: any,\n { dataSources: _dataSources }: any,\n ) => {\n return Promise.resolve([\n \"DAI\",\n \"FTE\",\n \"GUSD\",\n \"MKR\",\n \"USDC\",\n \"USDP\",\n \"USDT\",\n ]);\n },\n multiCurrencySeries: async (\n _: any,\n { filter }: any,\n { dataSources }: any,\n ) => {\n const queryEngine: AnalyticsModel = dataSources.db.Analytics;\n const results = await queryEngine.multiCurrencyQuery(filter);\n\n return results.map((s) => ({\n ...s,\n rows: s.rows.map((r: any) => ({\n ...r,\n dimensions: Object.keys(r.dimensions).map((d) => ({\n name: d,\n path: r.dimensions[d][\"path\"],\n icon: r.dimensions[d][\"icon\"],\n label: r.dimensions[d][\"label\"],\n description: r.dimensions[d][\"description\"],\n })),\n })),\n }));\n },\n },\n};\n","import type { AnalyticsQueryEngine } from \"@powerhousedao/analytics-engine-core\";\nimport {\n AnalyticsGranularity,\n AnalyticsPath,\n type AnalyticsQuery,\n} from \"@powerhousedao/analytics-engine-core\";\nimport { DateTime } from \"luxon\";\n\nexport type queryFilter = {\n start?: string;\n end?: string;\n granularity?: string;\n metrics: string[];\n dimensions: [Record<string, string>];\n currency?: string;\n};\n\ntype CurrencyConversion = {\n metric: string;\n sourceCurrency: string;\n};\n\ntype MultiCurrencyFilter = queryFilter & {\n conversions: CurrencyConversion[];\n};\n\nexport class AnalyticsModel {\n queryLogger: (query: AnalyticsQuery) => void;\n\n constructor(\n public readonly engine: AnalyticsQueryEngine,\n queryLogger?: (query: AnalyticsQuery) => void,\n ) {\n this.queryLogger = queryLogger || (() => {});\n }\n\n public async query(filter: queryFilter) {\n if (!filter) {\n return [];\n }\n\n const query: AnalyticsQuery = {\n start: filter.start ? DateTime.fromISO(filter.start) : null,\n end: filter.end ? DateTime.fromISO(filter.end) : null,\n granularity: getGranularity(filter.granularity),\n metrics: filter.metrics,\n currency: getCurrency(filter.currency),\n select: {},\n lod: {},\n };\n\n if (query.start && !query.start.isValid) {\n query.start = null;\n }\n\n if (query.end && !query.end.isValid) {\n query.end = null;\n }\n\n if (filter.dimensions.length < 1) {\n throw new Error(\"No dimensions provided\");\n } else {\n filter.dimensions.forEach((dimension) => {\n query.select[dimension.name] = [\n AnalyticsPath.fromString(dimension.select),\n ];\n query.lod[dimension.name] = Number(dimension.lod);\n });\n }\n\n this.queryLogger(query);\n\n const results = await this.engine.execute(query);\n\n // convert dates again\n const convertedResults = results.map((r) => ({\n ...r,\n start: r.start.toJSDate(),\n end: r.end.toJSDate(),\n }));\n\n return convertedResults;\n\n // TODO: pull caching interface out into analytics module\n //return measureAnalyticsQueryPerformance('analyticsQuery', 'analyticsQuery', query, false, \"high\");\n }\n\n public async multiCurrencyQuery(filter: MultiCurrencyFilter) {\n if (!filter) {\n return [];\n }\n\n const query: AnalyticsQuery = {\n start: filter.start ? DateTime.fromISO(filter.start) : null,\n end: filter.end ? DateTime.fromISO(filter.end) : null,\n granularity: getGranularity(filter.granularity),\n metrics: filter.metrics,\n currency: getCurrency(filter.currency),\n select: {},\n lod: {},\n };\n\n if (query.start && !query.start.isValid) {\n query.start = null;\n }\n\n if (query.end && !query.end.isValid) {\n query.end = null;\n }\n\n if (filter.dimensions.length < 1) {\n throw new Error(\"No dimensions provided\");\n } else {\n filter.dimensions.forEach((dimension) => {\n query.select[dimension.name] = [\n AnalyticsPath.fromString(dimension.select),\n ];\n query.lod[dimension.name] = Number(dimension.lod);\n });\n }\n\n this.queryLogger(query);\n\n return this.engine.executeMultiCurrency(query, {\n targetCurrency: query.currency,\n conversions: filter.conversions.map((c) => {\n return {\n metric: c.metric,\n currency: getCurrency(c.sourceCurrency),\n };\n }),\n });\n }\n\n public async getDimensions() {\n return await this.engine.getDimensions();\n }\n\n public getCurrencies(): Promise<string[]> {\n // todo: use knex inside of the analytics engine to select distinct currencies\n return Promise.resolve([\"DAI\", \"FTE\", \"MKR\", \"USDC\", \"USDP\", \"USDT\"]);\n }\n}\n\nconst getGranularity = (\n granularity: string | undefined,\n): AnalyticsGranularity => {\n switch (granularity) {\n case \"hourly\": {\n return AnalyticsGranularity.Hourly;\n }\n case \"daily\": {\n return AnalyticsGranularity.Daily;\n }\n case \"weekly\": {\n return AnalyticsGranularity.Weekly;\n }\n case \"monthly\": {\n return AnalyticsGranularity.Monthly;\n }\n case \"quarterly\": {\n return AnalyticsGranularity.Quarterly;\n }\n case \"semiAnnual\": {\n return AnalyticsGranularity.SemiAnnual;\n }\n case \"annual\": {\n return AnalyticsGranularity.Annual;\n }\n case \"total\": {\n return AnalyticsGranularity.Total;\n }\n default: {\n return AnalyticsGranularity.Total;\n }\n }\n};\n\nconst getCurrency = (currency: string | undefined) => {\n return currency ? AnalyticsPath.fromString(currency) : undefined;\n};\n","export const typedefs = `\ntype AnalyticsQuery {\n series(filter: AnalyticsFilter): [AnalyticsPeriod]\n multiCurrencySeries(filter: MultiCurrencyConversions): [AnalyticsPeriod]\n metrics: [String]\n dimensions: [Dimension]\n currencies: [String]\n}\n\ntype AnalyticsPeriod {\n period: String\n start: DateTime\n end: DateTime\n rows: [AnalyticsSeries]\n}\n\ntype AnalyticsSeries {\n dimensions: [AnalyticsSeriesDimension]\n metric: String\n unit: String\n value: Float\n sum: Float\n}\n\ntype AnalyticsSeriesDimension {\n name: String\n path: String\n label: String\n description: String\n icon: String\n}\n\ntype Dimension {\n name: String\n values: [Value]\n}\n\ntype Value {\n path: String\n label: String\n description: String\n icon: String\n}\n\nenum AnalyticsGranularity {\n hourly\n daily\n weekly\n monthly\n quarterly\n semiAnnual\n annual\n total\n}\n\ninput AnalyticsFilterDimension {\n name: String!\n select: String!\n lod: Int!\n}\n\ninput MultiCurrencyConversions {\n start: String\n end: String\n \"Period to group by\"\n granularity: AnalyticsGranularity\n \"List of metrics to filter by, such as 'budget' or 'actuals'\"\n metrics: [String]\n \"List of dimensions to filter by, such as 'budget' or 'project'\"\n dimensions: [AnalyticsFilterDimension]\n currency: String\n conversions: [CurrencyConversion]!\n}\n\ninput CurrencyConversion {\n metric: String!\n sourceCurrency: String!\n}\n\ninput AnalyticsFilter {\n start: String\n end: String\n \"Period to group by\"\n granularity: AnalyticsGranularity\n \"List of metrics to filter by, such as 'budget' or 'actuals'\"\n metrics: [String]\n \"List of dimensions to filter by, such as 'budget' or 'project'\"\n dimensions: [AnalyticsFilterDimension]\n currency: String\n}\n\nextend type Query {\n analytics: AnalyticsQuery\n}\n`;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerhousedao/analytics-engine-graphql",
3
- "version": "6.1.0-dev.2",
3
+ "version": "6.1.0-dev.20",
4
4
  "license": "AGPL-3.0-only",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "luxon": "3.7.2",
26
- "@powerhousedao/analytics-engine-core": "6.1.0-dev.2"
26
+ "@powerhousedao/analytics-engine-core": "6.1.0-dev.20"
27
27
  },
28
28
  "devDependencies": {
29
29
  "vitest": "4.1.1",