public ISqlFrom Join(J direction, ISqlTable clause, ISqlOn onClause) => Join(new SqlJoin(direction, clause, onClause));
public static string On(ISqlOn onRaw) => onRaw != null ? $"{S.On} {Clause(onRaw)}" : null;
public ISqlFrom RightJoin(ISqlTable clause, ISqlOn onClause) => Join(J.Right, clause, onClause);
public ISqlFrom OuterJoin(ISqlTable clause, ISqlOn onClause) => Join(J.Outer, clause, onClause);
public ISqlFrom InnerJoin(ISqlTable clause, ISqlOn onClause) => Join(J.Inner, clause, onClause);
public ISqlFrom LeftJoin(ISqlTable clause, ISqlOn onClause) => Join(J.Left, clause, onClause);
public ISqlJoin OuterJoin(ISqlTable obj, ISqlOn clause) => Join(J.Outer, obj, clause);
public ISqlJoin Join(J direction, ISqlTable obj, ISqlOn clause) => Join(new SqlJoin(direction, obj, clause));
public ISqlJoin RightJoin(ISqlTable obj, ISqlOn clause) => Join(J.Right, obj, clause);
public ISqlJoin LeftJoin(ISqlTable obj, ISqlOn clause) => Join(J.Left, obj, clause);
public ISqlJoin InnerJoin(ISqlTable obj, ISqlOn clause) => Join(J.Inner, obj, clause);
public ISqlJoin On(ISqlOn clause) => Chain(() => OnRaw = clause);
public SqlJoin(J direction, ISqlTable obj, ISqlOn clause) { DirectionRaw = direction; TableRaw = obj; OnRaw = clause; }