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

SettingGateway v2.1 #179

Merged
merged 90 commits into from Feb 25, 2018
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
d89ea96
SGv2.1 refactor
kyranet Feb 9, 2018
783a2c7
Fixed deploy
kyranet Feb 9, 2018
1d5c940
Now for real
kyranet Feb 9, 2018
d29b9e7
Make unused gateways lightning fast, updated changelog, fixed cache
kyranet Feb 9, 2018
596cc50
SchemaPiece#modify -> edit, GatewayDriver#types type from string[] to…
kyranet Feb 9, 2018
39c6606
MDLint
kyranet Feb 9, 2018
25e43ed
Fixed deploy
kyranet Feb 9, 2018
d51dc6c
Docs fixes
kyranet Feb 9, 2018
4f00b79
Removed ConfigUpdateEntryMany, tweaked docs, added toJSON to Gateway …
kyranet Feb 9, 2018
e149295
only decent way to document Symbol.iterator
bdistin Feb 9, 2018
156890c
Requested changes
kyranet Feb 9, 2018
b875eac
IterableIterator -> Iterator
kyranet Feb 9, 2018
379e089
Added iterator for Schedule
kyranet Feb 9, 2018
9f888cd
Updated changelog
kyranet Feb 9, 2018
b58902a
Removed `SchemaFolder#getList` and replaced it to `Configuration#list`.
kyranet Feb 9, 2018
7a4e081
First functional version
kyranet Feb 9, 2018
80209f1
Removed the abstract method `resolveString()` from SchemaFolder and S…
kyranet Feb 10, 2018
8584951
Fixed path.resolveString
kyranet Feb 10, 2018
4bd6f4c
whoops
kyranet Feb 10, 2018
77fb2e4
Fixed disabledCommands' validator
kyranet Feb 10, 2018
c3e5e91
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 10, 2018
1a7a8d4
Updated typings
kyranet Feb 10, 2018
6b54a74
Fixed Configuration#resolveString not parsing the keys correctly
kyranet Feb 10, 2018
8aebcca
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 13, 2018
2ae8c11
removeKey/Folder -> remove, hasKey -> has, improvements, code reduction
kyranet Feb 14, 2018
baae345
More memory improvements, bugfixes
kyranet Feb 14, 2018
74846a5
perf(iterators), removed Configuration#resetConfiguration
kyranet Feb 15, 2018
f71d42f
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 15, 2018
eca5fd4
SchemaFolder#add
kyranet Feb 18, 2018
ffdbe34
Forgot to call the function
kyranet Feb 18, 2018
d8b7c6d
Configuration#reset
kyranet Feb 18, 2018
12005d8
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 18, 2018
2e4f237
Bugfixes
kyranet Feb 18, 2018
6d7a91f
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 18, 2018
c4a653e
Update Client.js
kyranet Feb 18, 2018
22ec3d5
Updated resolvers to not include Promise<> in returns when async
kyranet Feb 18, 2018
a43bbba
Removed Promise<> in all JSDocs for methods with async
kyranet Feb 18, 2018
c000551
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 18, 2018
0797361
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 18, 2018
2848ddc
Merge remote-tracking branch 'origin/master' into SettingGateway-Refa…
kyranet Feb 19, 2018
26095d4
Merge branch 'master' into SettingGateway-Refactor
kyranet Feb 19, 2018
c686e16
Fixed SchemaFolder#add
kyranet Feb 19, 2018
a016927
Fixed old cache methods
kyranet Feb 19, 2018
72c0cdf
Fixed Configuration#reset() not creating the right object
kyranet Feb 19, 2018
1f07d15
Added `Configuration#reset(string[]);`
kyranet Feb 19, 2018
f2d8f34
Fixed an edge case in super-nested keys
kyranet Feb 19, 2018
4427dca
Fixed deep merger
kyranet Feb 19, 2018
17c5094
Fix Configuration._patch
kyranet Feb 19, 2018
c4248ef
Fixed critical bug in SGv2 shard support
kyranet Feb 19, 2018
0f85f86
Generate better SchemaPiece defaults
kyranet Feb 19, 2018
bd6040a
Fixed a bug
kyranet Feb 19, 2018
ff927c1
Better defaults
kyranet Feb 19, 2018
3b8944e
Fixed example running off the site
kyranet Feb 19, 2018
982c4a1
Fixed example for GatewayDriver#add
kyranet Feb 19, 2018
3d24e03
Give the example some sense
kyranet Feb 19, 2018
4c78f13
(typedef) emoji -> Emoji
kyranet Feb 19, 2018
ed97624
Fixed Emoji in RM and RD, RichMenuEmojisObject extend RichDisplayEmoj…
kyranet Feb 19, 2018
d191462
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 20, 2018
72d9e84
Merge branch 'master' into SettingGateway-Refactor
bdistin Feb 20, 2018
861efbf
Way much safer and faster Configuration#_merge
kyranet Feb 22, 2018
be7d9e8
Configuration refactor
kyranet Feb 23, 2018
bead707
Merge branch 'master' into SettingGateway-Refactor
kyranet Feb 23, 2018
67aa0f1
Fix Configuration merge
kyranet Feb 23, 2018
1fe5c56
Fix a little issue
kyranet Feb 23, 2018
3eac3ab
Return a better error if getPath returns null in silent mode
kyranet Feb 23, 2018
9c00073
Fix Gateway#getPath
kyranet Feb 23, 2018
e46b259
Actually fix it
kyranet Feb 23, 2018
78d8895
Whoops
kyranet Feb 23, 2018
a2840d3
Fixed save not accessing to the right tuple
kyranet Feb 23, 2018
5014d9e
Refactored the updateMany pattern
kyranet Feb 23, 2018
2f4309b
Revert accidental .eslintrc.json change
kyranet Feb 23, 2018
540f975
Fixed getPath, again
kyranet Feb 23, 2018
abe0ddc
Fix getPath, finally
kyranet Feb 23, 2018
9c745d9
Fixed another typo in Configuration#_setValueByPath
kyranet Feb 23, 2018
983794d
Fix Configuration#_setValueByPath not updating correctly
kyranet Feb 23, 2018
4d3bf30
Fixed Util.deepClone and SchemaFolder#_shardSyncSchema
kyranet Feb 23, 2018
fa13068
Added overload for Configuration#reset, added COMMAND_CONF_NOCHANGE t…
kyranet Feb 23, 2018
cad228d
Changelog
kyranet Feb 23, 2018
fbc9625
Ao's request
kyranet Feb 24, 2018
2f7d631
Add KlasaClient#options docs, updated events, fixed typo in KlasaUser…
kyranet Feb 24, 2018
58a2109
Typo
kyranet Feb 24, 2018
a4d6db2
Removed all `@memberof` from jsdocs, removed duplicated/useless typedefs
kyranet Feb 24, 2018
c1953c5
Don't show folders if they don't have any configurable keys
kyranet Feb 24, 2018
e9f54f0
Fixed Configuration#resolveString not getting the right values
kyranet Feb 24, 2018
484177a
Fixed ESLint
kyranet Feb 24, 2018
120970c
Fixed Configuration#get calling itself recursively instead of Configu…
kyranet Feb 24, 2018
f61d9e2
Fixed resetAll pattern not resetting nested keys
kyranet Feb 24, 2018
352b505
Merge branch 'master' into SettingGateway-Refactor
kyranet Feb 24, 2018
4816162
Typings fixes
kyranet Feb 24, 2018
fe4b1ec
Merge branch 'master' into SettingGateway-Refactor
kyranet Feb 25, 2018
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,10 @@ NOTE: For the contributors, you add new entries to this document following this

### Added

- [[#179](https://github.com/dirigeants/klasa/pull/179)] Added `Gateway#toJSON()` and `GatewayDriver#toJSON()`. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Added `GatewayDriver#register` to be able to register new gateways without events (directly in your `app.js`). (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Added `util.getIdentifier` as a replacement for the function validator. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Added `SchemaFolder#keys()`, `SchemaFolder#values()`, `SchemaFolder#entries()` and `SchemaFolder#[@@iterator]()`. Identical to Map's respective methods. (kyranet)
- [[#176](https://github.com/dirigeants/klasa/pull/176)] Added `categorychannel` type to `ArgResolver`. (kyranet)
- [[#166](https://github.com/dirigeants/klasa/pull/166)] Added support for TypeScript's `export default` in the loader. (kyranet)
- [[#162](https://github.com/dirigeants/klasa/pull/162)] Added better dependent arguments support. (bdistin)
Expand Down Expand Up @@ -81,6 +85,9 @@ NOTE: For the contributors, you add new entries to this document following this

### Changed

- [[#179](https://github.com/dirigeants/klasa/pull/179)] Changed the type for `GatewayDriver#types` from `string[]` to `Set<string>`. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Renamed `SchemaPiece#modify()` to `SchemaPiece#edit()`. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Renamed `Gateway#getKeys()` and `Gateway#getValues()` to `Gateway#getAllKeys()` and `Gateway#getAllValues()` respectively. (kyranet)
- [[#176](https://github.com/dirigeants/klasa/pull/176)] Marked several constructors as private (singleton, abstract or discouraged). (kyranet)
- [[#162](https://github.com/dirigeants/klasa/pull/162)] Modified the built-in conf command to use `dependant arguments`-like arguments using custom arguments and messages. (bdistin)
- [[#162](https://github.com/dirigeants/klasa/pull/162)] **[BREAKING]** Refactored ArgResolver. Now they take `arg`, `possible` and `msg` as parameters instead of `arg`, `currentUsage`, `possible`, `repeat` and `msg`. Repeating handling is now done in the backends. (bdistin)
Expand Down Expand Up @@ -133,6 +140,11 @@ NOTE: For the contributors, you add new entries to this document following this

### Removed

- [[#179](https://github.com/dirigeants/klasa/pull/179)] Removed the `ConfigUpdateEntryMany` typedef in favor of a more constant type. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Removed the resolver functions from constants. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Removed `SchemaFolder#keys` (`Map<string>`) to reduce RAM usage and key caching duplication. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Removed SettingGateway function validators. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Removed Collection cache provider (will be moved to klasa-pieces). (kyranet)
- [[#159](https://github.com/dirigeants/klasa/pull/159)] Removed deprecated property `GatewayOptions.cache` to be locked to `'collection'`. (kyranet)
- [[#158](https://github.com/dirigeants/klasa/pull/158)] `Configuration#updateMany` is now under `Configuration#update`, in favor of a much less confusing naming. (kyranet)
- [[`5b0c468362`](https://github.com/dirigeants/klasa/commit/5b0c46836200a57577bbd4aaa5cd463089a3bff0)] Removed `KlasaClient.sharded` as `Client.shard` is now fixed. (bdistin)
Expand All @@ -154,6 +166,8 @@ NOTE: For the contributors, you add new entries to this document following this

### Fixed

- [[#179](https://github.com/dirigeants/klasa/pull/179)] Fixed SettingResolver's return types. (kyranet)
- [[#179](https://github.com/dirigeants/klasa/pull/179)] Fixed Gateway syncing keys even when it's unused. (kyranet)
- [[#176](https://github.com/dirigeants/klasa/pull/176)] Fixed internal parser ignoring `0` as `min` and/or `max` due to falsy value check. (kyranet)
- [[#170](https://github.com/dirigeants/klasa/pull/170)] Fixed guild resolvables not working correctly. (kyranet)
- [[#165](https://github.com/dirigeants/klasa/pull/165)] Updated url for peer dependency `discord.js` and fixed all `JSDocs`. (kyranet)
Expand Down
19 changes: 19 additions & 0 deletions guides/.docconfig.json
Expand Up @@ -79,6 +79,25 @@
"path": "CommandsCustomResolvers.md"
}]
},
{
"name": "Advanced SettingGateway",
"files": [{
"name": "Understanding SchemaFolders",
"path": "UnderstandingSchemaFolders.md"
},
{
"name": "Understanding SchemaPieces",
"path": "UnderstandingSchemaPieces.md"
},
{
"name": "SettingGateway's Types",
"path": "SettingGatewayKeyTypes.md"
},
{
"name": "Updating your Configuration",
"path": "SettingGatewayConfigurationUpdate.md"
}]
},
{
"name": "Other Subjects",
"files": [{
Expand Down
@@ -0,0 +1,38 @@
# Updating your configuration

Once we have our schema done with all the keys, folders and types needed, we may want to update our configuration via SettingGateway, all of this is done via {@link Configuration#update}. However, how can I update it? Use any of the following code snippets:

```javascript
// Updating the value of a key
// This key is contained in the roles folder, and the second value is a role id, we also need
// to pass a GuildResolvable.
msg.guild.configs.update('roles.administrator', '339943234405007361', msg.guild);

// Updating an array
// userBlacklist, as mentioned in another tutorial, it's a piece with an array of users. Using
// the following code will add or remove it, depending on the existence of the key in the configuration.
msg.guild.configs.update('userBlacklist', '272689325521502208');

// Ensuring the function call adds (error if it exists)
msg.guild.configs.update('userBlacklist', '272689325521502208', { action: 'add' });

// Ensuring the function call removes (error if it doesn't exist)
msg.guild.configs.update('userBlacklist', '272689325521502208', { action: 'remove' });

// Updating it with a json object
// It's the same as the first code snippet. However, this pattern is slower.
msg.guild.configs.update({ roles: { administrator: '339943234405007361' } }, msg.guild);

// Updating multiple keys (only possible with json object)
msg.guild.configs.update({ prefix: 'k!', language: 'es-ES' });
```

> **Note**: Some types require a Guild instance to work, for example, *channels*, *roles* and *members*.

> Additionally, if no 'action' option is passed to {@link ConfigurationUpdateOptions}, it'll assume the `auto` mode, which will add or remove depending on the existence of the key.

## Further Reading:

- {@tutorial UnderstandingSchemaPieces}
- {@tutorial UnderstandingSchemaFolders}
- {@tutorial SettingGatewayKeyTypes}
66 changes: 66 additions & 0 deletions guides/Advanced SettingGateway/SettingGatewayKeyTypes.md
@@ -0,0 +1,66 @@
# SettingGateway's Types

By default, there are several built-in types that the developer can use, and with the possibility to add custom types via {@link Extendable}s as explained below. The built-in types are:

| Name | Type | Description |
| ------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **any** | Anything, no type restriction | Resolves anything, even objects. The usage of this type will make a key unconfigurable |
| **boolean** | A {@link Boolean} resolvable | Resolves a boolean primitive value |
| **categorychannel** | A {@link external:CategoryChannel} instance or id | Resolves a CategoryChannel |
| **channel** | A {@link external:Channel} instance or id | Resolves a channel. Be careful with using this, as it accepts any type of channel |
| **command** | A {@link Command} instance or name | Resolves a Command |
| **emoji** | An {@link external:Emoji} instance or name | Resolves a custom emoji |
| **float** | A floating point number | Resolves a [float](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) |
| **guild** | A {@link KlasaGuild} instance or id | Resolves a KlasaGuild (which extends Guild) |
| **integer** | An integer number | Resolves an [integer](https://en.wikipedia.org/wiki/Integer) number |
| **language** | A {@link Language} instance or name | Resolves a language |
| **member** | A {@link external:GuildMember} instance or id | Resolves a GuildMember |
| **msg** | A {@link KlasaMessage} instance or id | Resolves a KlasaMessage (which extends Message) |
| **role** | A {@link external:Role} instance or id | Resolves a Role |
| **string** | A {@link external:StringResolvable} | Resolves a string |
| **textchannel** | A {@link external:TextChannel} instance or id | Resolves a TextChannel |
| **url** | An URL resolvable | Resolves a URL with Node.js' URL parser |
| **user** | A {@link KlasaUser} instance or id | Resolves a KlasaUser (which extends User) |
| **voicechannel** | A {@link external:VoiceChannel} instance or id | Resolves a VoiceChannel |

## Adding new types

To add new types, you use an {@link Extendable} extending {@link SettingResolver}. If you don't know how to create an extendable, check the following tutorial: {@tutorial CreatingExtendables}. The following extendable is a template for this:

```javascript
const { Extendable } = require('klasa');

module.exports = class extends Extendable {

constructor(...args) {
super(...args, ['SettingResolver'], {
name: 'typeName',
klasa: true
});
}

/**
* Resolves my custom type!
* @param {*} data The data to resolve
* @param {KlasaGuild} guild The guild to resolve for
* @param {string} name The name of the key being resolved
* @param {Object} [minMax={}] The minimum and maximum
* @param {?number} minMax.min The minimum value
* @param {?number} minMax.max The maximum value
* @returns {Promise<*>}
*/
async extend(data, guild, name, { min, max } = {}) {
// The content
return data;
}

};
```

> **Note**: If a type does not load, you can add the type name to {@link GatewayDriver#types}, but it must be before the {@link SchemaPiece}s init as they check if the type is included in that Set.

## Further Reading:

- {@tutorial UnderstandingSchemaPieces}
- {@tutorial UnderstandingSchemaFolders}
- {@tutorial SettingGatewayConfigurationUpdate}
157 changes: 157 additions & 0 deletions guides/Advanced SettingGateway/UnderstandingSchemaFolders.md
@@ -0,0 +1,157 @@
# Understanding Schema

A schema works like a diagram or a blueprint, in SettingGateway, the schema defines the keys present in the configuration for a specific gateway. This feature serves multiple purposes:

1. Define what keys the {@link Gateway} manages and their properties.
1. Define what type the keys must hold.
1. Define the SQL schema when using a SQL database.
1. Speed up performance when iterating over keys.

## Adding keys

Adding keys with the schema is like adding a piece into a box, but you can also have boxes inside other boxes. That being said, you get the box you want to modify and insert the new pieces or boxes into it. The methods to achieve that are {@link SchemaFolder#addKey} to add pieces (keys) and {@link SchemaFolder#addFolder} to add boxes (folders).

You would normally use these two methods using the following snippet:

```javascript
// Add a new key
this.client.gateways.gatewayName.schema.addKey(name, options, force);

// Add a new folder
this.client.gateways.gatewayName.schema.addFolder(name, options, force);
```

The parameters are:

- **name**: The name of the new key. If it conflicts with a pre-existent key, this will error.
- **options**: The options for the new key or folder. Check {@link SchemaFolderAddOptions}.
- **force**: Whether this change should affect all entries. It requires a lot of processing but ensures the changes are correctly applied in both the cache and database.

You can also extend any of the three built-in {@link Gateway}s from Klasa. For example, if you want to add a new key called **modlogs** that accepts only text channels, for your guild configs, you would use the following code:

```javascript
this.client.gateways.guilds.schema.addKey('modlogs', { type: 'TextChannel' });
```

Where you're doing the following steps:

1. Access to {@link KlasaClient#gateways}, type of {@link GatewayDriver}, which holds all gateways.
1. Access to the guilds' {@link Gateway}, which manages the per-guild configuration.
1. Access to the guilds' schema via {@link Gateway#schema}, which manages the gateway's schema.
1. Add a new key called **modlogs** in the root of the schema, with a type of **TextChannel**.

And you would have a perfectly configured modlogs key in your configs. However, you can also have an array of the same type. For example, you want to have a configurable array of users blacklisted in a guild, in a key named **userBlacklist**:

```javascript
this.client.gateways.guilds.schema.addKey('userBlacklist', { type: 'User', array: true });
```

And now you can have access to any of them in your guild configs like in the following snippet!

```javascript
msg.guild.configs.modlogs;
// null
msg.guild.configs.userBlacklist;
// []
```

## Removing keys

Removing keys with the schema is quite easy, as you would have access to the {@link SchemaFolder} that holds it and remove it by its name (remember that `force` is optional and defaults to `true`) using {@link SchemaFolder#removeKey} as in the following example:

```javascript
this.client.gateways.gatewayName.schema.removeKey(name, force);
```

In case you have a key you do not longer use and you want to get rid of it, for example, the recently created **userBlacklist** key for guild configs, you would run the following code:

```javascript
this.client.gateways.guilds.schema.removeKey('userBlacklist');
```

And the property `userBlacklist` for all guild configs will be deleted.

## Adding folders

Folder creation is very similar to key creation, but with one key difference: it has no options for itself, but instead, it can create its children keys (just like you can add a box with other boxes and pieces, into another). You can add a new key inside a new folder in two different ways:

### Slower

You can create a folder, then create the keys, however, this will iterate over all entries twice:

```javascript
async function init() {
const { schema } = this.client.gateways.guilds;

await schema.addFolder('channels');
await schema.channels.addKey('modlogs', { type: 'TextChannel' });
console.log(schema.channels.modlogs.toJSON());
// {
// type: 'textchannel',
// array: false,
// default: null,
// min: null,
// max: null,
// configurable: true
// }
}
```

### Faster

However, it's possible to create a folder with all the sub-keys (and even more nested folders) with the folder creation.

```javascript
async function init() {
const { schema } = this.client.gateways.guilds;

await schema.addFolder('channels', { modlogs: { type: 'TextChannel' } });
console.log(schema.channels.modlogs.toJSON());
// {
// type: 'textchannel',
// array: false,
// default: null,
// min: null,
// max: null,
// configurable: true
// }
}
```

> **Reminder**: To access a key inside a folder in your configuration command, you use the access operator (`.`). For example: *k!conf set channels.modlogs #modlogs*

## Removing folders

It's exactly the same as {@link SchemaFolder#removeKey}, but using {@link SchemaFolder#removeFolder} instead. With the following syntax:

```javascript
this.client.gateways.gatewayName.schema.removeFolder(name, force);
```

To remove a folder, like the aforementioned **channels** folder, you would run the following code:

```javascript
this.client.gateways.guilds.schema.removeFolder('channels');
```

This will remove all the data from all the sub-keys and sub-folders, even very nested ones.

## Ensuring the existence of a key.

In [klasa pieces](https://github.com/dirigeants/klasa-pieces/) specially, some pieces require a key from the configuration to work, however, the creator of the pieces does not know if the user who downloads the piece has it, so this function becomes useful in this case.

```javascript
async function init() {
const { schema } = this.client.gateways.guilds;

if (!schema.hasKey('modlog')) {
await schema.addKey('modlog', { type: 'TextChannel' });
}
}
```

## Further Reading:

- {@tutorial UnderstandingSchemaPieces}
- {@tutorial SettingGatewayKeyTypes}
- {@tutorial SettingGatewayConfigurationUpdate}