Skip to content

Instantly share code, notes, and snippets.

@deanlandolt
Last active August 29, 2015 14:20
Show Gist options
  • Save deanlandolt/ce62bb9795525ebe90b1 to your computer and use it in GitHub Desktop.
Save deanlandolt/ce62bb9795525ebe90b1 to your computer and use it in GitHub Desktop.
Typescript interfaces and classes as DAL model specifications
// Typescript interfaces and classes as DAL model specifications
/**
* @entity
*/
class IndexedEntity {
/**
* The @id annotation defines primary key, implies @unique, @index
*
* @id
*/
id : string;
/**
* The @unique annotation an also be used to look up identity, implies @index
*
* @unique
*/
altId : number;
/**
* The @index field defines an attribute index, no additioanl constraints
*
* @index
*/
indexed : string;
/**
* Plain, unindexed field
*/
unindexed : string;
/**
* Accessor fields can be defined, not reified in generated entity
*/
get computed() : [ string, number ] {
return [ this.unindexed, this.altId ];
}
/**
* Accessors used to create compound fields, may also be @index or @unique
*
* @index
*/
get compoundIndex() : [ string, number ] {
return [ this.foo, this.bar ]
}
}
/**
* @entity
*/
class CompoundKeyed {
foo : string;
bar : number;
/**
* Accessor can also be used to define a compound primary key
*
* @id
*/
get foobar() : [ string, number ] {
return this.foo, this.bar
}
}
/**
* Interfaces declared as entities can be define indexed attributes
*
* @entity
*/
interface IndexedThing {
foo? : string;
/**
* Indexes defined on an interface allow querying across entity classes
*
* @index
*/
bar : number;
}
/**
* Class entities implementing indexed interfacs inherit their indexes
*
* @entity
*/
class SomeThing implements IndexedThing {
/**
* Optional attribute can be indexed at entity level
*/
foo : string;
/**
* Already indexed at interface level, but can be indexed by entity if need be
*
* @index
*/
bar : number;
}
/**
* @entity
*/
class OtherThing implements IndexedThing {
bar : number;
}
/**
* Trait interfaces expose attributes symbols as static symbols on trait
*
* @entity
*/
trait interface SomeAttributes {
foo : number;
bar : boolean;
/**
* Traits declared as entities allow attribute index declarations too
*
* @index
*/
baz : string | number;
quux? : Array<boolean | number>;
}
/**
* @entity
*/
class AnotherThing implements IndexedThing, SomeAttributes {
// from IndexedThing interface
foo : string;
bar : number;
// from SomeAttributes interface trait
// `as` keyword makes trait symbol attribute available through `foo_` accessor
[SomeAttributes.foo] as foo_ : number;
// no alias for `bar` but you can still ref it by symbol to set a defualt value
[SomeAttributes.bar] : boolean = true;
// no alias for `baz` either, but it's still implicitly defined as a symbol
// unlike interfaces, trait attribute defs can be elided as they won't conflict
// even though `quux` is optional it still gets a symbol defined for type checking
}
// trait interfacees can be used to create instances directly
var attrs = SomeAttributes({ foo: 123, bar: true, baz: '', quux: [1, true, 3] });
// attribute values can be referenced through their symbol or string name
attrs.foo === attrs[SomeAttributes.foo] === 123;
// this can be helpful when initializing entities with required trait attrs
var thing = new AnotherThing(Object.assign({ foo: '', bar: 0 }, attrs));
// traits and interfaces declared as entities can be queried directly
db.query`${IndexedThing.bar} < 1000`;
db.query`${SomeAttributes.baz} >= 'A' && ${SomeAttributes.baz} < 'D'`;
// Implementation notes:
// trait interface could be implemented as a strait-forward rewriting pass
// split trait interface into interface and class implementations
// class exposes all properties as static symbols
// interface defined using symbols for all implementing class properties
// add any `as` aliases as accessors into symbol values
// add type declarations for any elided trait attribute symbols
// but typescript has no support for symbols
// in the meantime, we could rewrite as symbol-like properties for type checking
// we could transform symbol-likes to real symbol instances in a post-compile pass
// if we're rewriting anyway, we may as well add syntax support for annotations too
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment