Git Product home page Git Product logo

tdm's Introduction

TDM - Typed data models

Data access object library for TypeScript, highly extensible, super typed.

TDM is built on top of the low level libraries @tdm/tixin, tdm/transformation, @tdm/core.

TDM relays on adapters, currently the only adapter is for Angular 2.

Status - Alpha.

Main packages:

@tdm/transformation

Extensible metadata storage and a Class transformation library (serialize / deserialize)

@Exclude()
export class MyClass {
 
  @Identity()
  @Prop()
  id: number;
  
  @Prop()
  name: string;
}

Supports custom mapping (transforming) implementations. Comes with a built in direct mapper. Direct mapping means 1:1 mapping, no schema or document structure.

A JSON API mapper can be used in @tdm/json-api-mapper

Create custom mappers by implementing the required interface.

@tdm/transformation comes with basic relationship (@Relation) support.

@tdm/core

Core library, extends @tdm/transformation and the active record pattern. @tdm/core comes with a lot of features...

  • Customizable Action based commands
  • Build in CRUD actions
  • Advanced Relationships (BelongsTo, Owns)
  • Static/instance level Actions (e.g.: query is always static)
  • Hooks for built in actions
  • Adapter architecture
  • Event stream (using observables)
  • DAO pattern
  • Active records pattern with full Type support. (need to opt in)
  • more..

@tdm/angular-forms-mapper (name might change)

Map data models defined with @tdm/transformation and @tdm/core into and back from @angular/forms FormGroup / FormArray

@tdm/angular-http (name might change)

An adapter implementation for the angular (2) library.

With @tdm/angular-http Model classes become Resource much like in angular 1 ng-resource but now with full typescript Type support for model properties, methods and Active record methods.

This is an Active record implementation, you can also go pure and use a DAO leaving your models clean.

@HttpResource({
  endpoint: '/api/users/:id?',
  urlParams: {
    limit: '5' // not in endpoint so will fallback to query string
  },
  noBuild: true
})
class User_ {

  @Identity()
  @UrlParam({ // optionally set what methods to use the param on.
    methods: [HttpActionMethodType.Get,
              HttpActionMethodType.Delete,
              HttpActionMethodType.Patch,
              HttpActionMethodType.Put]
  }) id: number; // this will go into the "endpoint" from the instance!

  @Prop({
    validation: { // custom validation
      name: 'test-validator',
      validate(ctx) {
        return false;
      },
      errorMessage(ctx) {
        return 'validation error';
      }
    }
  })
  username: string;


  @Prop({
    alias: 'motto_abc' // server returns motto_abc
  })
  @Exclude()
  motto: string;

  constructor() { }

  @Hook({event: 'before', action: '$refresh'})
  bfRef() {
    console.log('BeforeRefresh');
  }

  @HttpAction({ // custom HTTP actions
    method: HttpActionMethodType.Get,
    raw: {
      handler: User_.prototype.rawDeserializedHandler,
      deserialize: true
    }
  })
  rawDeserialized: (options?: HttpActionOptions) => RestMixin<User_>;
  private rawDeserializedHandler(resp: ExecuteResponse, options?: HttpActionOptions) {
  }

  @HttpAction({
    method: HttpActionMethodType.Get,
    raw: User_.prototype.rawHandler
  })
  raw: (options?: HttpActionOptions) => RestMixin<User_>;
  private rawHandler(resp: ExecuteResponse, options?: HttpActionOptions) {
  }


  @Hook({event: 'before', action: 'query'}) // static hooks (for static actions, like query)
  static bfQuery(this: ActiveRecordCollection<RestMixin<User_>>) {
    this.$ar.next()
      .then( coll => {
        console.log(`BeforeQuery-AfterQuery: got ${coll.collection.length}`)
      });
    console.log('BeforeQuery');
  }

  @ExtendAction({ // extending a built in action, useful if you need the user to provide more params)
    pre: (ctx: ExecuteContext<any>, id: IdentityValueType, a:number, b: number, options: HttpActionOptions) => {
      ctx.data[ctx.adapterStore.identity] = id;
      return options;
    }
  })
  static find: (id: IdentityValueType, a:number, b: number, options?: HttpActionOptions) => RestMixin<User_>;
}

export const User = RestMixin(User_);
export type User = RestMixin<User_>;

You can also do

@HttpResource({
  endpoint: '/api/users/:id?',
  urlParams: { // there are hard coded params
    limit: '5' // not in path so will go to query string (?param=15)
  },
})
export class User extends RestMixin(User_) { }

TDM supports multiple ways to declare a Resource, you can see them all in src/demo/resource/Users
Using RestMixin is mandatory, at least until the TypeScript team will implement type reflection for ClassDecorator

@tdm/angular-http Supports AOT but currently Resources are not injectable!

You can then use the resources:

User.find(2).username;                             // OK
const user: User = new User();                     // OK
user.id = 15;
user.$refresh().username;                                          // OK
user.$refresh().abcd;                                                // SHOULD ERROR

// Using async system with promises:
user.$ar.next().then( u => u.id );                                   // OK
user.$ar.next().then( u => u.f34 );                                  // SHOULD ERROR

// hadnling collections, coll.collection is of type User[]
UserBaseClass.query().$ar.next().then(coll => coll.collection );     // OK
UserBaseClass.query().$ar.next().then(coll => coll.sdfd );           // SHOULD ERROR

// Using async system with observables
user.$ar.events$.subscribe(...)

// `$events` is an observable of resource events (succes, failure, cancelled etc...)



// Cacnelling 
user.$ar.cancel()

// disconnecting all observables
user.$ar.disconnect()

// busy (in-flight) indicator
user.$ar.busy // true / false

// busy (in-flight) indicator STREAM
user.$ar.busy$.subscribe(...) // true / false

The $ar object is an optional extension, you can opt in via import '@tdm/core/add/active-record-state';

The promise extension next() is optional extension, you can opt in via import '@tdm/core/add/active-record-state/next';

tdm's People

Watchers

James Drew avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.