ソースを参照

Start implementation of data adapters

Provide basic file structure for JSONL adapter.
feature/data-adapters
コミット
cc1edf60eb
7個のファイルの変更118行の追加28行の削除
  1. +76
    -0
      src/adapters/file-jsonl/adapter.ts
  2. +1
    -0
      src/adapters/file-jsonl/common.ts
  3. +2
    -0
      src/adapters/file-jsonl/index.ts
  4. +1
    -0
      src/adapters/index.ts
  5. +33
    -27
      src/index.ts
  6. +5
    -0
      src/sources/index.ts
  7. +0
    -1
      src/sources/kanjidic/index.ts

+ 76
- 0
src/adapters/file-jsonl/adapter.ts ファイルの表示

@@ -0,0 +1,76 @@
import { createWriteStream } from 'fs';
import { readFile } from 'fs/promises';
import { ADAPTER_ID } from './common';

export interface CreateAdapterParams {
type: typeof ADAPTER_ID;
path: string;
}

class Adapter<Entry = unknown, Query extends Record<string, unknown> = Record<string, unknown>> {
private data?: Entry[];

private readonly path: string;

constructor(path: string) {
this.path = path;
}

async connect() {
const buf = await readFile(this.path);
const str = buf.toString('utf-8');
const json = str.split('\n');
this.data = json.map((j) => JSON.parse(j) as Entry);
}

async createIngester() {
return Promise.resolve(createWriteStream(this.path));
}

async search(query: Query): Promise<Entry[]> {
if (!this.data) {
throw new Error('Adapter not initialized.');
}

const results = this.data.filter((dd) => (
Object.entries(query).reduce(
(prevFilterResult, [key, value]) => {
const d = dd as Record<string, unknown>;
if (typeof d[key] === 'string') {
const dString = d[key] as string;
return (
prevFilterResult
&& dString.toLowerCase().includes((value as string).toString().toLowerCase())
);
}
if (typeof d[key] === 'number') {
return prevFilterResult && Number(d[key]) === Number(value);
}
return prevFilterResult && d[key] === value;
},
true,
)
));

return Promise.resolve(results);
}
}

export const createAdapter = async (params: Omit<CreateAdapterParams, 'type'>) => {
const { path } = params;

const adapter = new Adapter(path);
await adapter.connect();
};

export interface CreateIngesterParams {
type: typeof ADAPTER_ID;
path: string;
}

export const createIngester = async (params: Omit<CreateIngesterParams, 'type'>) => {
const { path } = params;

const adapter = new Adapter(path);
return adapter.createIngester();
};

+ 1
- 0
src/adapters/file-jsonl/common.ts ファイルの表示

@@ -0,0 +1 @@
export const ADAPTER_ID = 'file-jsonl' as const;

+ 2
- 0
src/adapters/file-jsonl/index.ts ファイルの表示

@@ -0,0 +1,2 @@
export * from './common';
export * from './adapter';

+ 1
- 0
src/adapters/index.ts ファイルの表示

@@ -0,0 +1 @@
export * as FileJsonl from './file-jsonl';

+ 33
- 27
src/index.ts ファイルの表示

@@ -1,42 +1,48 @@
import * as KanjidicImpl from './sources/kanjidic';
import * as JMdictImpl from './sources/jmdict';
import * as JMnedictImpl from './sources/jmnedict';
import * as RadKFileImpl from './sources/radkfile';
import * as KRadFileImpl from './sources/kradfile';

const SUPPORTED_SOURCES = [
KanjidicImpl,
JMdictImpl,
JMnedictImpl,
RadKFileImpl,
KRadFileImpl,
] as const;
import * as SupportedSources from './sources';
import * as SupportedAdapters from './adapters';

export * as Sources from './sources';
export * as Adapters from './adapters';
export * from './streams';

export type CreateDownloaderParams = (
KanjidicImpl.CreateDownloaderParams
| JMdictImpl.CreateDownloaderParams
| JMnedictImpl.CreateDownloaderParams
| RadKFileImpl.CreateDownloaderParams
| KRadFileImpl.CreateDownloaderParams
SupportedSources.Kanjidic.CreateDownloaderParams
| SupportedSources.JMdict.CreateDownloaderParams
| SupportedSources.JMnedict.CreateDownloaderParams
| SupportedSources.RadKFile.CreateDownloaderParams
| SupportedSources.KRadFile.CreateDownloaderParams
);

export * as Kanjidic from './sources/kanjidic';
export * as JMdict from './sources/jmdict';
export * as JMnedict from './sources/jmnedict';
export * as RadKFile from './sources/radkfile';
export * as KRadFile from './sources/kradfile';
export * from './streams';

export const createDownloader = (params: CreateDownloaderParams) => {
const { type: sourceType, ...etcParams } = params;
const theSupportedSources = Object.values(SupportedSources);

const theSourceModule = SUPPORTED_SOURCES
const theSourceModule = theSupportedSources
.find((videoTypeModule) => videoTypeModule.SOURCE_ID === sourceType);

if (!theSourceModule) {
const validSourceTypes = SUPPORTED_SOURCES.map((videoTypeModule) => videoTypeModule.SOURCE_ID).join(', ');
const validSourceTypes = theSupportedSources.map((videoTypeModule) => videoTypeModule.SOURCE_ID).join(', ');
throw new TypeError(`Invalid source type: "${sourceType}". Valid values are: ${validSourceTypes}`);
}

return theSourceModule.createDownloader(etcParams);
};

export type CreateAdapterParams = (
SupportedAdapters.FileJsonl.CreateAdapterParams
);

export const createAdapter = (params: CreateAdapterParams) => {
const { type: adapterType, ...etcParams } = params;
const theSupportedAdapters = Object.values(SupportedAdapters);

const theAdapterModule = theSupportedAdapters
.find((adapterTypeModule) => adapterTypeModule.ADAPTER_ID === adapterType);

if (!theAdapterModule) {
const validAdapterTypes = theSupportedAdapters.map((adapterTypeModule) => adapterTypeModule.ADAPTER_ID).join(', ');
throw new TypeError(`Invalid adapter type: "${adapterType}". Valid values are: ${validAdapterTypes}`);
}

return theAdapterModule.createAdapter(etcParams);
};

+ 5
- 0
src/sources/index.ts ファイルの表示

@@ -0,0 +1,5 @@
export * as Kanjidic from './kanjidic';
export * as JMdict from './jmdict';
export * as JMnedict from './jmnedict';
export * as RadKFile from './radkfile';
export * as KRadFile from './kradfile';

+ 0
- 1
src/sources/kanjidic/index.ts ファイルの表示

@@ -1,3 +1,2 @@
export * from './common';
export * from './downloader';


読み込み中…
キャンセル
保存