#126 : ODManagers now use Maps instead of Arrays
This results in a minor speed increase within large managers (e.g. builders, tickets, blacklist, ...)
This commit is contained in:
+124
-88
@@ -54,11 +54,27 @@ export type ODDiscordIdType = "role"|"server"|"channel"|"category"|"user"|"membe
|
|||||||
*/
|
*/
|
||||||
export class ODId {
|
export class ODId {
|
||||||
/**The full value of this `ODId` as a `string`. */
|
/**The full value of this `ODId` as a `string`. */
|
||||||
value: string
|
#value: string
|
||||||
/**The source of the id (text before `:`). (e.g. `openticket` for all built-in ids) */
|
/**The full value of this `ODId` as a `string`. */
|
||||||
|
set value(id:string){
|
||||||
|
this._change(this.#value,id)
|
||||||
|
this.#value = id
|
||||||
|
}
|
||||||
|
get value(){
|
||||||
|
return this.#value
|
||||||
|
}
|
||||||
|
/**The source of the id (text before `:`). (e.g. `openticket` for all built-in ids)
|
||||||
|
*
|
||||||
|
* @deprecated Replaced with `getNamespace()` and will be removed in `v4.1.0`.
|
||||||
|
*/
|
||||||
source: string
|
source: string
|
||||||
/**The identifier of the id (text after `:`). */
|
/**The identifier of the id (text after `:`).
|
||||||
|
*
|
||||||
|
* @deprecated Replaced with `getIdentifier()` and will be removed in `v4.1.0`.
|
||||||
|
*/
|
||||||
identifier: string
|
identifier: string
|
||||||
|
/**The change listener for the parent `ODManager` of this `ODId`. */
|
||||||
|
#change: ((oldId:string,newId:string) => void)|null = null
|
||||||
|
|
||||||
constructor(id:ODValidId){
|
constructor(id:ODValidId){
|
||||||
if (typeof id != "string" && !(id instanceof ODId)) throw new ODSystemError("Invalid constructor parameter => id:ODValidId")
|
if (typeof id != "string" && !(id instanceof ODId)) throw new ODSystemError("Invalid constructor parameter => id:ODValidId")
|
||||||
@@ -74,10 +90,10 @@ export class ODId {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result.length > 0) this.value = result.join("")
|
if (result.length > 0) this.#value = result.join("")
|
||||||
else throw new ODSystemError("invalid ID at 'new ODID(id: "+id+")'")
|
else throw new ODSystemError("invalid ID at 'new ODID(id: "+id+")'")
|
||||||
|
|
||||||
const splitted = this.value.split(":")
|
const splitted = this.#value.split(":")
|
||||||
if (splitted.length > 1){
|
if (splitted.length > 1){
|
||||||
this.source = splitted[0]
|
this.source = splitted[0]
|
||||||
splitted.shift()
|
splitted.shift()
|
||||||
@@ -88,7 +104,7 @@ export class ODId {
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
//id is ODId
|
//id is ODId
|
||||||
this.value = id.value
|
this.#value = id.#value
|
||||||
this.source = id.source
|
this.source = id.source
|
||||||
this.identifier = id.identifier
|
this.identifier = id.identifier
|
||||||
}
|
}
|
||||||
@@ -96,7 +112,36 @@ export class ODId {
|
|||||||
|
|
||||||
/**Returns a string representation of this id. (same as `this.value`) */
|
/**Returns a string representation of this id. (same as `this.value`) */
|
||||||
toString(){
|
toString(){
|
||||||
return this.value
|
return this.#value
|
||||||
|
}
|
||||||
|
/**The namespace of the id before `:`. (e.g. `openticket` for `openticket:autoclose-enabled`) */
|
||||||
|
getNamespace(){
|
||||||
|
const splitted = this.#value.split(":")
|
||||||
|
if (splitted.length > 1) return splitted[0]
|
||||||
|
else return ""
|
||||||
|
}
|
||||||
|
/**The identifier of the id after `:`. (e.g. `autoclose-enabled` for `openticket:autoclose-enabled`) */
|
||||||
|
getIdentifier(){
|
||||||
|
const splitted = this.#value.split(":")
|
||||||
|
if (splitted.length > 1){
|
||||||
|
splitted.shift()
|
||||||
|
return splitted.join(":")
|
||||||
|
}else return this.#value
|
||||||
|
}
|
||||||
|
/**Trigger an `onChange()` event in the parent `ODManager` of this class. */
|
||||||
|
protected _change(oldId:string,newId:string){
|
||||||
|
if (this.#change){
|
||||||
|
try{
|
||||||
|
this.#change(oldId,newId)
|
||||||
|
}catch(err){
|
||||||
|
process.emit("uncaughtException",err)
|
||||||
|
throw new ODSystemError("Failed to execute _change() callback!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/****(❌ SYSTEM ONLY!!)** Set the callback executed when a value inside this class changes. */
|
||||||
|
changed(callback:((oldId:string,newId:string) => void)|null){
|
||||||
|
this.#change = callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +172,8 @@ export class ODManagerChangeHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**## ODManagerRedirectHelper `class`
|
/**## ODManagerRedirectHelper `class`
|
||||||
|
* @deprecated ### Will be removed in Open Ticket `v4.1.0`!
|
||||||
|
*
|
||||||
* This is Open Ticket ticket manager redirect helper.
|
* This is Open Ticket ticket manager redirect helper.
|
||||||
*
|
*
|
||||||
* It is used to redirect a source to another source when the id isn't found.
|
* It is used to redirect a source to another source when the id isn't found.
|
||||||
@@ -206,8 +253,8 @@ export class ODManager<DataType extends ODManagerData> extends ODManagerChangeHe
|
|||||||
#debug?: ODDebugger
|
#debug?: ODDebugger
|
||||||
/**The message to send when debugging this manager. */
|
/**The message to send when debugging this manager. */
|
||||||
#debugname?: string
|
#debugname?: string
|
||||||
/**An array storing all data classes ❌ **(don't edit unless really needed!)***/
|
/**The map storing all data classes in this manager. */
|
||||||
#data: DataType[] = []
|
#data: Map<string,DataType> = new Map()
|
||||||
/**An array storing all listeners when data is added. */
|
/**An array storing all listeners when data is added. */
|
||||||
#addListeners: ODManagerAddCallback<DataType>[] = []
|
#addListeners: ODManagerAddCallback<DataType>[] = []
|
||||||
/**An array storing all listeners when data has changed. */
|
/**An array storing all listeners when data has changed. */
|
||||||
@@ -223,7 +270,7 @@ export class ODManager<DataType extends ODManagerData> extends ODManagerChangeHe
|
|||||||
this.#debugname = debugname
|
this.#debugname = debugname
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Add data to the manager. The id will be fetched from the data class! You can optionally select to overwrite existing data!*/
|
/**Add data to the manager. The `ODId` in the data class will be used as identifier! You can optionally select to overwrite existing data!*/
|
||||||
add(data:DataType|DataType[], overwrite?:boolean): boolean {
|
add(data:DataType|DataType[], overwrite?:boolean): boolean {
|
||||||
//repeat same command when data is an array
|
//repeat same command when data is an array
|
||||||
if (Array.isArray(data)){
|
if (Array.isArray(data)){
|
||||||
@@ -233,106 +280,94 @@ export class ODManager<DataType extends ODManagerData> extends ODManagerChangeHe
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//add listener for data id change => transfer data within manager
|
||||||
|
data.id.changed((oldId,newId) => {
|
||||||
|
this.#data.delete(oldId)
|
||||||
|
this.#data.set(newId,data)
|
||||||
|
})
|
||||||
|
|
||||||
//add data
|
//add data
|
||||||
const existIndex = this.#data.findIndex((d) => d.id.value === data.id.value)
|
let didOverwrite: boolean
|
||||||
if (existIndex < 0){
|
if (this.#data.has(data.id.value)){
|
||||||
this.#data.push(data)
|
|
||||||
if (this.#debug) this.#debug.debug("Added new "+this.#debugname+" to manager",[{key:"id",value:data.id.value},{key:"overwrite",value:"false"}])
|
|
||||||
|
|
||||||
//change listeners
|
|
||||||
data.changed(() => {
|
|
||||||
//notify change in upper-manager (because data in this manager changed)
|
|
||||||
this._change()
|
|
||||||
this.#changeListeners.forEach((cb) => {
|
|
||||||
try{
|
|
||||||
cb(data)
|
|
||||||
}catch(err){
|
|
||||||
throw new ODSystemError("Failed to run manager onChange() listener.\n"+err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
//add listeners
|
|
||||||
this.#addListeners.forEach((cb) => {
|
|
||||||
try{
|
|
||||||
cb(data,false)
|
|
||||||
}catch(err){
|
|
||||||
throw new ODSystemError("Failed to run manager onAdd() listener.\n"+err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
//notify change in upper-manager (because data added)
|
|
||||||
this._change()
|
|
||||||
|
|
||||||
return false
|
|
||||||
}else{
|
|
||||||
if (!overwrite) throw new ODSystemError("Id '"+data.id.value+"' already exists in "+this.#debugname+" manager. Use 'overwrite:true' to allow overwriting!")
|
if (!overwrite) throw new ODSystemError("Id '"+data.id.value+"' already exists in "+this.#debugname+" manager. Use 'overwrite:true' to allow overwriting!")
|
||||||
this.#data[existIndex] = data
|
this.#data.set(data.id.value,data)
|
||||||
|
didOverwrite = true
|
||||||
if (this.#debug) this.#debug.debug("Added new "+this.#debugname+" to manager",[{key:"id",value:data.id.value},{key:"overwrite",value:"true"}])
|
if (this.#debug) this.#debug.debug("Added new "+this.#debugname+" to manager",[{key:"id",value:data.id.value},{key:"overwrite",value:"true"}])
|
||||||
|
|
||||||
//change listeners
|
}else{
|
||||||
data.changed(() => {
|
this.#data.set(data.id.value,data)
|
||||||
//notify change in upper-manager (because data in this manager changed)
|
didOverwrite = false
|
||||||
this._change()
|
if (this.#debug) this.#debug.debug("Added new "+this.#debugname+" to manager",[{key:"id",value:data.id.value},{key:"overwrite",value:"false"}])
|
||||||
this.#changeListeners.forEach((cb) => {
|
|
||||||
try{
|
|
||||||
cb(data)
|
|
||||||
}catch(err){
|
|
||||||
throw new ODSystemError("Failed to run manager onChange() listener.\n"+err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
//add listeners
|
}
|
||||||
this.#addListeners.forEach((cb) => {
|
|
||||||
|
//emit change listeners
|
||||||
|
data.changed(() => {
|
||||||
|
//notify change in upper-manager (because data in this manager changed)
|
||||||
|
this._change()
|
||||||
|
this.#changeListeners.forEach((cb) => {
|
||||||
try{
|
try{
|
||||||
cb(data,true)
|
cb(data)
|
||||||
}catch(err){
|
}catch(err){
|
||||||
throw new ODSystemError("Failed to run manager onAdd() listener.\n"+err)
|
throw new ODSystemError("Failed to run manager onChange() listener.\n"+err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
//notify change in upper-manager (because data added)
|
//emit add listeners
|
||||||
this._change()
|
this.#addListeners.forEach((cb) => {
|
||||||
|
try{
|
||||||
|
cb(data,didOverwrite)
|
||||||
|
}catch(err){
|
||||||
|
throw new ODSystemError("Failed to run manager onAdd() listener.\n"+err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return true
|
//notify change in upper-manager (because data added)
|
||||||
}
|
this._change()
|
||||||
|
|
||||||
|
return didOverwrite
|
||||||
}
|
}
|
||||||
/**Get data that matches the `ODId`. Returns the found data.*/
|
/**Get data that matches the `ODId`. Returns the found data.*/
|
||||||
get(id:ODValidId): DataType|null {
|
get(id:ODValidId): DataType|null {
|
||||||
const newId = new ODId(id)
|
const newId = new ODId(id)
|
||||||
const d = this.#data.find((a) => a.id.value == newId.value)
|
const data = this.#data.get(newId.value)
|
||||||
if (d) return d
|
if (data) return data
|
||||||
else{
|
else{
|
||||||
const redirect = this.redirects.list().find((redirect) => redirect.fromSource === newId.source)
|
//DEPRECATED!!!
|
||||||
|
const redirect = this.redirects.list().find((redirect) => redirect.fromSource === newId.getNamespace())
|
||||||
if (!redirect) return null
|
if (!redirect) return null
|
||||||
else{
|
else{
|
||||||
const redirectId = new ODId(redirect.toSource+":"+newId.identifier)
|
const redirectId = new ODId(redirect.toSource+":"+newId.getIdentifier())
|
||||||
return this.get(redirectId)
|
return this.get(redirectId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**Remove data that matches the `ODId`. Returns the removed data.*/
|
/**Remove data that matches the `ODId`. Returns the removed data. */
|
||||||
remove(id:ODValidId): DataType|null {
|
remove(id:ODValidId): DataType|null {
|
||||||
const newId = new ODId(id)
|
const newId = new ODId(id)
|
||||||
const index = this.#data.findIndex((a) => a.id.value == newId.value)
|
const data = this.#data.get(newId.value)
|
||||||
if (index < 0){
|
|
||||||
const redirect = this.redirects.list().find((redirect) => redirect.fromSource === newId.source)
|
if (!data){
|
||||||
|
//DEPRECATED!!!
|
||||||
|
const redirect = this.redirects.list().find((redirect) => redirect.fromSource === newId.getNamespace())
|
||||||
if (!redirect){
|
if (!redirect){
|
||||||
if (this.#debug) this.#debug.debug("Removed "+this.#debugname+" from manager",[{key:"id",value:newId.value},{key:"found",value:"false"}])
|
if (this.#debug) this.#debug.debug("Removed "+this.#debugname+" from manager",[{key:"id",value:newId.value},{key:"found",value:"false"}])
|
||||||
return null
|
return null
|
||||||
}else{
|
}else{
|
||||||
const redirectId = new ODId(redirect.toSource+":"+newId.identifier)
|
const redirectId = new ODId(redirect.toSource+":"+newId.getIdentifier())
|
||||||
return this.remove(redirectId)
|
return this.remove(redirectId)
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
this.#data.delete(newId.value)
|
||||||
|
if (this.#debug) this.#debug.debug("Removed "+this.#debugname+" from manager",[{key:"id",value:newId.value},{key:"found",value:"true"}])
|
||||||
}
|
}
|
||||||
if (this.#debug) this.#debug.debug("Removed "+this.#debugname+" from manager",[{key:"id",value:newId.value},{key:"found",value:"true"}])
|
|
||||||
const data = this.#data.splice(index,1)[0]
|
|
||||||
|
|
||||||
//change listeners
|
//remove all listeners
|
||||||
|
data.id.changed(null)
|
||||||
data.changed(null)
|
data.changed(null)
|
||||||
|
|
||||||
//remove listeners
|
//emit remove listeners
|
||||||
this.#removeListeners.forEach((cb) => {
|
this.#removeListeners.forEach((cb) => {
|
||||||
try{
|
try{
|
||||||
cb(data)
|
cb(data)
|
||||||
@@ -346,39 +381,40 @@ export class ODManager<DataType extends ODManagerData> extends ODManagerChangeHe
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
/**Check if data that matches the `ODId` exists. Returns a boolean.*/
|
/**Check if data that matches the `ODId` exists. Returns a boolean. */
|
||||||
exists(id:ODValidId): boolean {
|
exists(id:ODValidId): boolean {
|
||||||
const newId = new ODId(id)
|
const newId = new ODId(id)
|
||||||
const d = this.#data.find((a) => a.id.value == newId.value)
|
if (this.#data.has(newId.value)) return true
|
||||||
if (d) return true
|
|
||||||
else{
|
else{
|
||||||
const redirect = this.redirects.list().find((redirect) => redirect.fromSource === newId.source)
|
//DEPRECATED!!!
|
||||||
|
const redirect = this.redirects.list().find((redirect) => redirect.fromSource === newId.getNamespace())
|
||||||
if (!redirect) return false
|
if (!redirect) return false
|
||||||
else{
|
else{
|
||||||
const redirectId = new ODId(redirect.toSource+":"+newId.identifier)
|
const redirectId = new ODId(redirect.toSource+":"+newId.getIdentifier())
|
||||||
return this.exists(redirectId)
|
return this.exists(redirectId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**Get all data inside this manager*/
|
/**Get all data inside this manager*/
|
||||||
getAll(): DataType[] {
|
getAll(): DataType[] {
|
||||||
return [...this.#data]
|
return Array.from(this.#data.values())
|
||||||
}
|
}
|
||||||
/**Get all data that matches inside the filter function*/
|
/**Get all data that matches inside the filter function*/
|
||||||
getFiltered(predicate:(value:DataType, index:number, array:DataType[]) => unknown): DataType[] {
|
getFiltered(predicate:(value:DataType, index:number, array:DataType[]) => unknown): DataType[] {
|
||||||
return this.#data.filter(predicate)
|
return Array.from(this.#data.values()).filter(predicate)
|
||||||
}
|
}
|
||||||
/**Get all data that matches the regex*/
|
/**Get all data where the `ODId` matches the provided RegExp. */
|
||||||
getRegex(regex:RegExp): DataType[] {
|
getRegex(regex:RegExp): DataType[] {
|
||||||
return this.#data.filter((data) => regex.test(data.id.value))
|
return Array.from(this.#data.values()).filter((data) => regex.test(data.id.value))
|
||||||
}
|
}
|
||||||
/**Get the length of the data inside this manager*/
|
/**Get the length/size/amount of the data inside this manager. */
|
||||||
getLength(){
|
getLength(){
|
||||||
return this.#data.length
|
return this.#data.size
|
||||||
}
|
}
|
||||||
/**Get a list of all the ids inside this manager*/
|
/**Get a list of all the ids inside this manager*/
|
||||||
getIds(): ODId[] {
|
getIds(): ODId[] {
|
||||||
return this.#data.map((d) => d.id)
|
const ids = Array.from(this.#data.keys())
|
||||||
|
return ids.map((id) => new ODId(id))
|
||||||
}
|
}
|
||||||
/**Run an iterator over all data in this manager. This method also supports async-await behaviour!*/
|
/**Run an iterator over all data in this manager. This method also supports async-await behaviour!*/
|
||||||
async loopAll(cb:(data:DataType,id:ODId) => ODPromiseVoid): Promise<void> {
|
async loopAll(cb:(data:DataType,id:ODId) => ODPromiseVoid): Promise<void> {
|
||||||
|
|||||||
Reference in New Issue
Block a user