Skip to content
This repository has been archived by the owner on Nov 29, 2020. It is now read-only.

feat: First step at the rewrite #1

Merged
merged 46 commits into from
Dec 9, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c49f1ed
feat: First step at the rewrite
kyranet Nov 10, 2019
2a0d373
feat: Added more progress
kyranet Nov 10, 2019
eaff9ba
feat: Added more things
kyranet Nov 11, 2019
85398f7
git: Why do we not ignore yarn-error.log?
kyranet Nov 11, 2019
dfe163c
refactor: Move code around and finished Settings and GatewayDriver
kyranet Nov 11, 2019
968058f
misc: Deleted yarn-error.log
kyranet Nov 11, 2019
95d30e5
feat: Added all structures
kyranet Nov 11, 2019
fd50d31
lint: Fixed several ESLint warnings
kyranet Nov 11, 2019
869a33e
build: Resolved all build errors
kyranet Nov 11, 2019
5978f15
fix: Resovled circular references
kyranet Nov 11, 2019
a8ac06f
tests: Added first mock classes and fixed a few things
kyranet Nov 11, 2019
ed6ab6f
tests: Add a bunch of tests and fixed a few things
kyranet Nov 29, 2019
d8e46a5
misc: More tests, finalized SG and fixed bugs
kyranet Nov 29, 2019
abd34f8
polyfill: Added ObjectFromEntries for Node.js v10 compatibility
kyranet Nov 29, 2019
0065363
misc: Fixed SchemaEntry#edit, added examples and tests
kyranet Nov 30, 2019
181716f
docs: I heard you liked examples
kyranet Nov 30, 2019
7eb7def
docs: Added more examples
kyranet Nov 30, 2019
4668d66
misc: Finalized SchemaEntry's tests, documented more, moved resolve m…
kyranet Nov 30, 2019
9761129
fix: Better `_checkSchemaFolder` and freeze SchemaEntry instances
kyranet Nov 30, 2019
5aae670
misc: Refactor code and added more tests
kyranet Dec 3, 2019
b857e36
tests: Fixed Settings tests
kyranet Dec 5, 2019
135e209
misc: Resolved bug in Settings upsert code, added more tests
kyranet Dec 5, 2019
73e7b6c
chore: Update all dependencies
kyranet Dec 6, 2019
b45dcc1
build: Enable declarationMap
kyranet Dec 6, 2019
a222327
ci: Use Crawl's action and Node.js 12
kyranet Dec 6, 2019
8a9bced
fix: Resolved several bugs and added more tests
kyranet Dec 6, 2019
0a2f808
tests: Removed snapshot testing
kyranet Dec 6, 2019
10ace57
tests: Added a lot of SettingsFolder#reset tests, fixed several things
kyranet Dec 6, 2019
60babae
tests: Finalize SettingsFolder#reset's tests
kyranet Dec 6, 2019
6d7c095
fix: Resolved several bugs and added some SF#update tests
kyranet Dec 8, 2019
c44bf95
fix: Resolved type issues and another bug
kyranet Dec 8, 2019
c9ae1f7
test: Added more SF#update tests and more hooks for Serializer
kyranet Dec 8, 2019
565a99e
tests: Added array action tests
kyranet Dec 9, 2019
e682de8
tests: Added ArrayIndex tests
kyranet Dec 9, 2019
69cf148
docs: Added LOTS OF DOCS
kyranet Dec 9, 2019
9e43f9d
docs: Added CHANGELOG
kyranet Dec 9, 2019
c8495ba
fix: Generate TS compiler error to stop unexpected behaviour.
kyranet Dec 9, 2019
74a4085
misc: Resolved code review by @vladfrangu
kyranet Dec 9, 2019
b4ec819
misc: Resolved code review by @Favna
kyranet Dec 9, 2019
105d652
git: Ignore all .xml and .log files
kyranet Dec 9, 2019
4df9f91
chore: Update all dependencies
kyranet Dec 9, 2019
5af9b29
package: Update the name, description, and repository.url
kyranet Dec 9, 2019
16e431a
npm: Add .github and remove unused/inexistent files
kyranet Dec 9, 2019
fc0ef32
Update src/lib/schema/Schema.ts
kyranet Dec 9, 2019
c6da24b
misc: Resolved all requested changes from @vladfrangu and @Favna
kyranet Dec 9, 2019
f7b38ca
style: Re-add `_` prefix to methods users are not supposed to use
kyranet Dec 9, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{
"extends": "klasa/eslint-ts"
"extends": "klasa/eslint-ts",
"rules": {
kyranet marked this conversation as resolved.
Show resolved Hide resolved
"no-dupe-class-members": 0,
"no-invalid-this": 0
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ coverage/
dist/
docs/
test-results.xml
yarn-error.log
12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@
"engines": {
"node": ">=10.1.0"
},
"peerDependencies": {
"klasa": "dirigeants/klasa"
},
"devDependencies": {
"@types/node": "^12.7.3",
"@types/ws": "^6.0.3",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"ava": "^2.3.0",
"discord.js": "discordjs/discord.js",
"eslint": "^6.3.0",
"eslint-config-klasa": "dirigeants/klasa-lint",
"klasa": "dirigeants/klasa#875/head",
"source-map-support": "^0.5.13",
"ts-node": "^8.3.0",
"typescript": "^3.6.2"
Expand All @@ -45,5 +51,11 @@
"ts-node/register",
"source-map-support/register"
]
},
"dependencies": {
"@discordjs/collection": "^0.1.3",
"@klasa/querybuilder": "^0.0.1",
"@klasa/request-handler": "^0.0.3",
"@klasa/utils": "^0.0.2"
}
}
17 changes: 14 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
export default function foo(): string {
return 'bar';
}
export * from './lib/gateway/Gateway';
export * from './lib/gateway/GatewayDriver';
export * from './lib/gateway/GatewayStorage';
export * from './lib/schema/Schema';
export * from './lib/schema/SchemaEntry';
export * from './lib/schema/SchemaFolder';
kyranet marked this conversation as resolved.
Show resolved Hide resolved
export * from './lib/settings/Settings';
export * from './lib/settings/SettingsFolder';
export * from './lib/structures/Provider';
export * from './lib/structures/SQLProvider';
export * from './lib/structures/ProviderStore';
export * from './lib/structures/Serializer';
export * from './lib/structures/SerializerStore';
export * from './lib/types';
75 changes: 75 additions & 0 deletions src/lib/gateway/Gateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { RequestHandler, IdKeyed } from '@klasa/request-handler';
import Collection from '@discordjs/collection';
import { GatewayStorage } from './GatewayStorage';
import { Settings } from '../settings/Settings';
import { Client } from '../types';

export class Gateway extends GatewayStorage {

/**
* The cached entries for this Gateway or the external datastore to get the settings from.
*/
kyranet marked this conversation as resolved.
Show resolved Hide resolved
public cache: ProxyMap = (this.name in this.client) && (this.client[this.name as keyof Client] instanceof Map) ?
this.client[this.name as keyof Client] as ProxyMap :
new Collection<string, ProxyMapEntry>();

/**
* The request handler that manages the synchronization queue.
*/
public requestHandler = new RequestHandler(
(id: string): Promise<IdKeyed<string>> => {
const { provider } = this;
if (provider === null) throw new Error('Cannot run requests without a provider available.');
kyranet marked this conversation as resolved.
Show resolved Hide resolved
return provider.get(this.name, id) as Promise<IdKeyed<string>>;
}, (ids: string[]): Promise<IdKeyed<string>[]> => {
const { provider } = this;
if (provider === null) throw new Error('Cannot run requests without a provider available.');
return provider.getAll(this.name, ids) as Promise<IdKeyed<string>[]>;
}
);

/**
* Gets an entry from the cache or creates one if it does not exist
* @param target The target that holds a Settings instance of the holder for the new one
* @param id The settings' identificator
*/
public acquire(target: IdKeyed<string>, id = target.id): Settings {
return this.get(id) || this.create(target, id);
}

/**
* Get an entry from the cache.
* @param id The key to get from the cache
*/
public get(id: string): Settings | null {
const entry = this.cache.get(id);
return (entry && entry.settings) || null;
}

/**
* Create a new Settings instance for this gateway.
* @param target The target that will hold this instance alive
* @param id The settings' identificator
*/
public create(target: IdKeyed<string>, id = target.id): Settings {
const settings = new Settings(this, target, id);
if (this.schema.size !== 0) settings.sync(true).catch(err => this.client.emit('error', err));
return settings;
}

/**
* Runs a synchronization task for the gateway.
*/
public async sync(): Promise<this> {
await this.requestHandler.wait();
return this;
}

}

export interface ProxyMapEntry {
settings: Settings;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
kyranet marked this conversation as resolved.
Show resolved Hide resolved
export interface ProxyMap extends Map<string, ProxyMapEntry> { }
kyranet marked this conversation as resolved.
Show resolved Hide resolved
49 changes: 49 additions & 0 deletions src/lib/gateway/GatewayDriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Collection from '@discordjs/collection';
import { GatewayStorage, GatewayStorageJson } from './GatewayStorage';
import { Client } from '../types';

export class GatewayDriver extends Collection<string, GatewayStorage> {

/**
* The client this GatewayDriver was created with.
*/
kyranet marked this conversation as resolved.
Show resolved Hide resolved
public readonly client: Client;

/**
* Constructs a new instance of GatewayDriver.
* @param client The client that manages this instance
*/
public constructor(client: Client) {
super();
this.client = client;
}

/**
* Registers a new gateway.
* @param gateway The gateway to register
*/
public register(gateway: GatewayStorage): this {
if (typeof this.client.options.settings.gateways === 'undefined') this.client.options.settings.gateways = {};
kyranet marked this conversation as resolved.
Show resolved Hide resolved
if (!(gateway.name in this.client.options.settings.gateways)) this.client.options.settings.gateways[gateway.name] = {};
this.set(gateway.name, gateway);
return this;
kyranet marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Initializes all gateways.
*/
public async init(): Promise<void> {
await Promise.all([...this.values()].map(gateway => gateway.init()));
}

/**
* The gateway driver with all serialized gateways.
*/
public toJSON(): GatewayDriverJson {
return Object.fromEntries([...this.entries()].map(([key, value]) => [key, value.toJSON()]));
}

}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
kyranet marked this conversation as resolved.
Show resolved Hide resolved
export interface GatewayDriverJson extends Record<string, GatewayStorageJson> { }
kyranet marked this conversation as resolved.
Show resolved Hide resolved
120 changes: 120 additions & 0 deletions src/lib/gateway/GatewayStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { Client } from '../types';
import { Schema, SchemaJson } from '../schema/Schema';
import { Provider } from '../structures/Provider';

export class GatewayStorage {

/**
* The client this gateway was created with.
*/
public readonly client: Client;

/**
* The name of this gateway.
*/
public readonly name: string;

/**
* The schema for this gateway.
*/
public readonly schema: Schema;

/**
* Whether or not this gateway has been initialized.
*/
public ready = false;

/**
* The provider's name that manages this gateway.
*/
private readonly _provider: string;
kyranet marked this conversation as resolved.
Show resolved Hide resolved

public constructor(client: Client, name: string, options: GatewayStorageOptions) {
this.client = client;
this.name = name;
this.schema = options.schema || new Schema();
this._provider = options.provider || client.options.providers.default || '';
kyranet marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* The provider that manages this gateway's persistent data.
*/
public get provider(): Provider | null {
return this.client.providers.get(this._provider) || null;
kyranet marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Initializes the gateway.
*/
public async init(): Promise<void> {
// Gateways must not initialize twice.
if (this.ready) throw new Error(`The gateway ${this.name} has already been initialized.`);
kyranet marked this conversation as resolved.
Show resolved Hide resolved

// Check the provider's existence.
const { provider } = this;
if (provider === null) throw new Error(`The gateway ${this.name} could not find the provider ${this._provider}.`);
kyranet marked this conversation as resolved.
Show resolved Hide resolved
this.ready = true;

const errors = [];
for (const entry of this.schema.values(true)) {
// Assign Client to all Pieces for Serializers && Type Checking
entry.client = this.client;

Object.freeze(entry);

// Check if the entry is valid
try {
entry.check();
} catch (error) {
errors.push(error.message);
}
}

if (errors.length) throw new Error(`[SCHEMA] There is an error with your schema.\n${errors.join('\n')}`);

// TODO(kyranet): Finish this.
// this.schema.defaults._init(this.schema.defaults, this.schema);

// // Init the table
// const hasTable = await provider.hasTable(this.name);
// if (!hasTable) await provider.createTable(this.name);

// // Add any missing columns (NoSQL providers return empty array)
// const columns = await provider.getColumns(this.name);
// if (columns.length) {
// const promises = [];
// for (const [key, entry] of this.schema.paths) if (!columns.includes(key)) promises.push(provider.addColumn(this.name, entry));
// await Promise.all(promises);
// }
}

/**
* Runs a synchronization task for the gateway.
*/
public async sync(): Promise<this> {
return this;
}

/**
* Get A JSON object containing the schema and the options.
*/
public toJSON(): GatewayStorageJson {
return {
name: this.name,
provider: this._provider,
kyranet marked this conversation as resolved.
Show resolved Hide resolved
schema: this.schema.toJSON()
};
}

}

export interface GatewayStorageOptions {
schema?: Schema;
provider?: string;
}

export interface GatewayStorageJson {
name: string;
provider: string;
schema: SchemaJson;
}