隐式转换无法处理对象键中的空格和非法字符
Implicit cast can't deal with spaces & illegal characters in Object keys
AlphaVantage API 键中有空格和句点。 API 没有正式的 doco,尽管你可以在他们的演示 url
中看到它
在我的 Typescript 应用程序中,我为此创建了数据结构(我很高兴任何人都可以复制和使用它们 - 也许在找到我的问题的解决方案之后):
export class MetaData {
'1. Information': string
'2. Symbol': string
'3. Last Refreshed': string
'4. Output Size': string
'5. Time Zone': string
constructor(one, two, three, four, five) {
this['1. Information'] = one
this['2. Symbol'] = two
this['3. Last Refreshed'] = three
this['4. Output Size'] = four
this['5. Time Zone'] = five
}
}
export interface TimeSeries {
[date: string]: {
'1. open': string;
'2. high': string;
'3. low': string;
'4. close': string;
'5. volume': string;
}
}
export interface AlphaVantage {
'Meta Data': MetaData;
'Time Series (Daily)'?: TimeSeries;
'Time Series (Weekly)'?: TimeSeries;
}
我使用 NPM 中的 alphavantage
调用 API 并将其隐式转换为我的 AlphaVantage
:
const av: AlphaVantage = await alpha.data.weekly(options.stocks, 'compact', 'json')
然后(可能经过一些按摩等)我将其保存在 MongoDB 集合中:
const doc = await this.model.findByIdAndUpdate(proxyModel._id, proxyModel)
(ProxyModel 是一个 DTO,用于定义数据库键,例如日期、股票代码等...其中一个字段是 AlphaVantage 数据)。
这必须序列化数据,它会出错:
key 1. Information must not contain '.'
有没有简单的方法来处理这个问题。我的选择是创建不带空格的等效对象:
export interface TimeSeries {
[date: string]: {
'1_open': string;
'2_high': string;
'3_low': string;
'4_close': string;
'5_volume': string;
}
}
然后投射到这个。在这种情况下提供映射 ...
我可以看到我自己正在创建一个实现。然而,在开始讨论之前,我想听听有关如何最好地处理此数据结构的任何想法。
我用一个简单的对象键映射函数写了一个解决方案。
我也尝试使用 AutoMapper-ts - https://www.npmjs.com/package/automapper-ts - so as to make it more clearer about the changes being made. However it became too difficult to map all cases. I couldn't get the tests (that act as doco) working in the time I allocated to it. I've just seen that there is https://github.com/gonza-lito/AutoMapper,这是最近修改的分支。然而,它并不是开箱即用的 npm install
ing。
这是我想出的class来解决我的问题:
export class ObjectUtils {
static fixKey(key) {
const upperCaseReplacer = (match: string, g1: string) => {
return g1.toUpperCase()
}
const wordsReplacer = (match: string, g1: string, g2: string) => {
return g1 + g2.toUpperCase()
}
const m1 = key.replace(/^\d+ *\. *([a-zA-Z])/, upperCaseReplacer)
const m2 = m1.replace(/([a-zA-Z]) +([a-zA-Z])/g, wordsReplacer)
const out = m2.replace(/^([a-zA-Z])/, upperCaseReplacer)
return out
}
static fixObj(obj: any) {
let newObj = null
if (Array.isArray(obj)) {
newObj = []
for (const i of obj) {
newObj.push(ObjectUtils.fixObj(i))
}
return newObj
} else if (typeof obj === 'object') {
newObj = {}
for (const key of Object.keys(obj)) {
newObj[ObjectUtils.fixKey(key)] = ObjectUtils.fixObj(obj[key])
}
return newObj
} else {
return obj
}
}
}
这将创建以下内容:
export class Metadata {
Information: string
Symbol: string
LastRefreshed: string
OutputSize: string
TimeZone: string
}
export interface TimeSeries {
[date: string]: {
Open: string;
High: string;
Low: string;
Close: string;
Volume: string;
}
}
export interface AlphaVantage {
Metadata: Metadata
DailyTimeSeries?: TimeSeries
WeeklyTimeSeries?: TimeSeries
}
AlphaVantage API 键中有空格和句点。 API 没有正式的 doco,尽管你可以在他们的演示 url
中看到它在我的 Typescript 应用程序中,我为此创建了数据结构(我很高兴任何人都可以复制和使用它们 - 也许在找到我的问题的解决方案之后):
export class MetaData {
'1. Information': string
'2. Symbol': string
'3. Last Refreshed': string
'4. Output Size': string
'5. Time Zone': string
constructor(one, two, three, four, five) {
this['1. Information'] = one
this['2. Symbol'] = two
this['3. Last Refreshed'] = three
this['4. Output Size'] = four
this['5. Time Zone'] = five
}
}
export interface TimeSeries {
[date: string]: {
'1. open': string;
'2. high': string;
'3. low': string;
'4. close': string;
'5. volume': string;
}
}
export interface AlphaVantage {
'Meta Data': MetaData;
'Time Series (Daily)'?: TimeSeries;
'Time Series (Weekly)'?: TimeSeries;
}
我使用 NPM 中的 alphavantage
调用 API 并将其隐式转换为我的 AlphaVantage
:
const av: AlphaVantage = await alpha.data.weekly(options.stocks, 'compact', 'json')
然后(可能经过一些按摩等)我将其保存在 MongoDB 集合中:
const doc = await this.model.findByIdAndUpdate(proxyModel._id, proxyModel)
(ProxyModel 是一个 DTO,用于定义数据库键,例如日期、股票代码等...其中一个字段是 AlphaVantage 数据)。
这必须序列化数据,它会出错:
key 1. Information must not contain '.'
有没有简单的方法来处理这个问题。我的选择是创建不带空格的等效对象:
export interface TimeSeries {
[date: string]: {
'1_open': string;
'2_high': string;
'3_low': string;
'4_close': string;
'5_volume': string;
}
}
然后投射到这个。在这种情况下提供映射 ...
我可以看到我自己正在创建一个实现。然而,在开始讨论之前,我想听听有关如何最好地处理此数据结构的任何想法。
我用一个简单的对象键映射函数写了一个解决方案。
我也尝试使用 AutoMapper-ts - https://www.npmjs.com/package/automapper-ts - so as to make it more clearer about the changes being made. However it became too difficult to map all cases. I couldn't get the tests (that act as doco) working in the time I allocated to it. I've just seen that there is https://github.com/gonza-lito/AutoMapper,这是最近修改的分支。然而,它并不是开箱即用的 npm install
ing。
这是我想出的class来解决我的问题:
export class ObjectUtils {
static fixKey(key) {
const upperCaseReplacer = (match: string, g1: string) => {
return g1.toUpperCase()
}
const wordsReplacer = (match: string, g1: string, g2: string) => {
return g1 + g2.toUpperCase()
}
const m1 = key.replace(/^\d+ *\. *([a-zA-Z])/, upperCaseReplacer)
const m2 = m1.replace(/([a-zA-Z]) +([a-zA-Z])/g, wordsReplacer)
const out = m2.replace(/^([a-zA-Z])/, upperCaseReplacer)
return out
}
static fixObj(obj: any) {
let newObj = null
if (Array.isArray(obj)) {
newObj = []
for (const i of obj) {
newObj.push(ObjectUtils.fixObj(i))
}
return newObj
} else if (typeof obj === 'object') {
newObj = {}
for (const key of Object.keys(obj)) {
newObj[ObjectUtils.fixKey(key)] = ObjectUtils.fixObj(obj[key])
}
return newObj
} else {
return obj
}
}
}
这将创建以下内容:
export class Metadata {
Information: string
Symbol: string
LastRefreshed: string
OutputSize: string
TimeZone: string
}
export interface TimeSeries {
[date: string]: {
Open: string;
High: string;
Low: string;
Close: string;
Volume: string;
}
}
export interface AlphaVantage {
Metadata: Metadata
DailyTimeSeries?: TimeSeries
WeeklyTimeSeries?: TimeSeries
}