Skip to content

Instantly share code, notes, and snippets.

@AustinEast
Last active February 21, 2020 22:58
Show Gist options
  • Save AustinEast/52b873e850c35cf5ed6e933240df21b7 to your computer and use it in GitHub Desktop.
Save AustinEast/52b873e850c35cf5ed6e933240df21b7 to your computer and use it in GitHub Desktop.
Simple Store Abstract For Haxe
using Math;
/**
* A Simple Store of Data that is accessible through Queries. It is Abstracted over the Array type, so casting between the two is supported.
*/
abstract Store<T>(Array<T>) from Array<T> to Array<T> {
public inline function new(?v:Array<T>) this = v == null ? [] : v;
/**
* Gets the first item that matches the Query.
*/
public inline function get(query:Query<T>):Null<QueryResult<T>> {
var min = (query.min == null ? 0 : query.min).min(this.length).max(0).floor();
var max = (query.max == null ? this.length : query.max).min(this.length).max(min).floor();
if (query.id != null) return query.id >= min && query.id <= max ? {
id: query.id,
item: this[query.id]
} : null;
var item = null;
var id = 0;
for (i in min...max) {
id = i;
item = this[i];
if (this[i] == null) continue;
// Check if the item matches all the values
if (query.values != null) for (j in 0...query.values.length) {
var val = Reflect.field(item, query.values[j].field);
if (val != null && val == query.values[j].value) continue;
item = null;
break;
}
// Check if the item matches the filter
if (item != null && query.filter != null && !query.filter(item)) item = null;
// If we have an item still, break out of the loop and return it
if (item != null) break;
}
return item == null ? null : {
id: id,
item: item
};
}
/**
* Gets all items that match the Query.
*/
public inline function get_all(query:Query<T>):Array<QueryResult<T>> {
var arr = [];
var min:Int = query.min == null ? 0 : query.min;
while (min < this.length) {
query.min = min;
var result = get(query);
if (result != null) {
arr.push(result);
min = result.id + 1;
}
else min = this.length;
}
return arr;
}
/**
* Gets the id of an item. If the item doesn't exist in the store, this returns -1.
* @param item The item to get the id for.
* @param from The starting id to search the Store for.
* @return The id of the item, or -1 if the item's id is not found.
*/
public inline function get_id(item:T, from:Int = 0):Int return this.indexOf(item, from);
/**
* Sets an item in the Store. If an id is not specified, the item is added as a new entry to the Store.
* @param item The item to set in the Store.
* @param id The id of the item. If not set, the item will be added as a new entry in the Store.
* @return The id of the item.
*/
public function set(item:T, ?id:Null<Int>):Int {
if (id != null) {
this[id] = item;
return id;
}
return this.push(item) - 1;
}
/**
* Adds an item to the Store.
* @param item The item to add to the Store.
* @return The id of the item.
*/
public inline function add(item:T):Int return set(item);
/**
* Adds an Array of items to the Store.
* @param items Array of items to add to the Store.
*/
public inline function add_all(items:Array<T>):Void for (v in items) add(v);
}
@:structInit
class Query<T> {
/**
* Id to search for items in a Store.
*/
@:optional public var id:Null<Int>;
/**
* Minimum id to search for items in a Store.
*/
@:optional public var min:Null<Int>;
/**
* Maximum id to search for items in a Store.
*/
@:optional public var max:Null<Int>;
/**
* Array of QueryValues to compare against items in a Store.
*/
@:optional public var values:Null<Array<QueryValue>>;
/**
* Method to filter items against in a Store.
*/
@:optional public var filter:Null<T->Bool>;
}
@:structInit
class QueryResult<T> {
/**
* Id of the Queried item.
*/
public var id:Int;
/**
* The Queried item.
*/
public var item:T;
public function toString() return 'QueryResult ( id: $id, item: $item )';
}
@:structInit
class QueryValue {
/**
* Name of the field to compare.
*/
public var field:String;
/**
* Value of the field to compare.
*/
public var value:Dynamic;
}
class Test {
/**
* Test usage of Store.hx
*/
static function main() {
// Create a new Store
var store = new Store<Person>();
// Add a bunch of items to the Store
for (i in 0...100) {
store.add(new Person());
}
// Get everyone named Bob who is over the age of 18
var results = store.get_all({
values: [{field: 'name', value: 'Bob'}],
filter: (person) -> return person.age > 18
});
// Change every found Bob's name to Rachel
for (result in results) result.item.name = 'Rachel';
// Get the Person with id 5
trace(store.get({
id: 5
}));
// Get all Bobs
trace(store.get_all({
values: [{field: 'name', value: 'Bob'}]
}));
// Get all Rachels
trace(store.get_all({
values: [{field: 'name', value: 'Rachel'}]
}));
// Get the first person with an age under 50
trace(store.get({
filter: (person) -> return person.age < 50
}));
}
}
class Person {
static var possible_names = ['Austin', 'Bob', 'Sandra'];
public var name:String;
public var age:Int;
public function new() {
name = possible_names[Std.random(3)];
age = Std.random(100);
}
public function toString() return '$name, age $age';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment