github.com/acoshift/pgsql@v0.15.3/pgstmt/select.go (about)

     1  package pgstmt
     2  
     3  // Select builds select statement
     4  func Select(f func(b SelectStatement)) *Result {
     5  	var st selectStmt
     6  	f(&st)
     7  	return newResult(build(st.make()))
     8  }
     9  
    10  // SelectStatement is the select statement builder
    11  type SelectStatement interface {
    12  	Distinct() Distinct
    13  	Columns(col ...any)
    14  	ColumnSelect(f func(b SelectStatement), as string)
    15  	ColumnExists(f func(b SelectStatement))
    16  	From(table ...string)
    17  	FromSelect(f func(b SelectStatement), as string)
    18  	FromValues(f func(b Values), as string)
    19  
    20  	Join(table string) Join
    21  	InnerJoin(table string) Join
    22  	FullOuterJoin(table string) Join
    23  	LeftJoin(table string) Join
    24  	RightJoin(table string) Join
    25  
    26  	JoinSelect(f func(b SelectStatement), as string) Join
    27  	InnerJoinSelect(f func(b SelectStatement), as string) Join
    28  	FullOuterJoinSelect(f func(b SelectStatement), as string) Join
    29  	LeftJoinSelect(f func(b SelectStatement), as string) Join
    30  	RightJoinSelect(f func(b SelectStatement), as string) Join
    31  
    32  	JoinLateralSelect(f func(b SelectStatement), as string) Join
    33  	InnerJoinLateralSelect(f func(b SelectStatement), as string) Join
    34  	FullOuterJoinLateralSelect(f func(b SelectStatement), as string) Join
    35  	LeftJoinLateralSelect(f func(b SelectStatement), as string) Join
    36  	RightJoinLateralSelect(f func(b SelectStatement), as string) Join
    37  
    38  	JoinUnion(f func(b UnionStatement), as string) Join
    39  	InnerJoinUnion(f func(b UnionStatement), as string) Join
    40  	FullOuterJoinUnion(f func(b UnionStatement), as string) Join
    41  	LeftJoinUnion(f func(b UnionStatement), as string) Join
    42  	RightJoinUnion(f func(b UnionStatement), as string) Join
    43  
    44  	Where(f func(b Cond))
    45  	GroupBy(col ...string)
    46  	Having(f func(b Cond))
    47  	OrderBy(col string) OrderBy
    48  	Limit(n int64)
    49  	Offset(n int64)
    50  }
    51  
    52  type Distinct interface {
    53  	On(col ...string)
    54  }
    55  
    56  type Values interface {
    57  	Value(value ...any)
    58  	Values(values ...[]any)
    59  }
    60  
    61  type OrderBy interface {
    62  	Asc() OrderBy
    63  	Desc() OrderBy
    64  	NullsFirst() OrderBy
    65  	NullsLast() OrderBy
    66  }
    67  
    68  type Join interface {
    69  	On(f func(b Cond))
    70  	Using(col ...string)
    71  }
    72  
    73  type selectStmt struct {
    74  	distinct *distinct
    75  	columns  group
    76  	from     group
    77  	joins    buffer
    78  	where    cond
    79  	groupBy  group
    80  	having   cond
    81  	orderBy  group
    82  	limit    *int64
    83  	offset   *int64
    84  }
    85  
    86  func (st *selectStmt) Distinct() Distinct {
    87  	st.distinct = &distinct{}
    88  	return st.distinct
    89  }
    90  
    91  func (st *selectStmt) Columns(col ...any) {
    92  	st.columns.push(col...)
    93  }
    94  
    95  func (st *selectStmt) ColumnSelect(f func(b SelectStatement), as string) {
    96  	var x selectStmt
    97  	f(&x)
    98  
    99  	var b buffer
   100  	b.push(paren(x.make()))
   101  	if as != "" {
   102  		b.push(as)
   103  	}
   104  	st.columns.push(&b)
   105  }
   106  
   107  func (st *selectStmt) ColumnExists(f func(b SelectStatement)) {
   108  	var x selectStmt
   109  	f(&x)
   110  
   111  	var b buffer
   112  	b.push("exists", paren(x.make()))
   113  	st.columns.push(&b)
   114  }
   115  
   116  func (st *selectStmt) From(table ...string) {
   117  	st.from.pushString(table...)
   118  }
   119  
   120  func (st *selectStmt) FromSelect(f func(b SelectStatement), as string) {
   121  	var x selectStmt
   122  	f(&x)
   123  
   124  	var b buffer
   125  	b.push(paren(x.make()))
   126  	if as != "" {
   127  		b.push(as)
   128  	}
   129  	st.from.push(&b)
   130  }
   131  
   132  func (st *selectStmt) FromValues(f func(b Values), as string) {
   133  	var x values
   134  	f(&x)
   135  
   136  	if x.empty() {
   137  		return
   138  	}
   139  
   140  	st.from.push(withGroup(" ",
   141  		withGroup(" ",
   142  			withParen(" ",
   143  				"values",
   144  				withGroup(", ", x.q...),
   145  			),
   146  		),
   147  		as,
   148  	))
   149  }
   150  
   151  func (st *selectStmt) join(typ, table string) Join {
   152  	var b buffer
   153  	b.push(table)
   154  	x := join{
   155  		typ:   typ,
   156  		table: &b,
   157  	}
   158  	st.joins.push(&x)
   159  	return &x
   160  }
   161  
   162  func (st *selectStmt) Join(table string) Join {
   163  	return st.join("join", table)
   164  }
   165  
   166  func (st *selectStmt) InnerJoin(table string) Join {
   167  	return st.join("inner join", table)
   168  }
   169  
   170  func (st *selectStmt) FullOuterJoin(table string) Join {
   171  	return st.join("full outer join", table)
   172  }
   173  
   174  func (st *selectStmt) LeftJoin(table string) Join {
   175  	return st.join("left join", table)
   176  }
   177  
   178  func (st *selectStmt) RightJoin(table string) Join {
   179  	return st.join("right join", table)
   180  }
   181  
   182  func (st *selectStmt) joinSelect(typ string, f func(b SelectStatement), as string) Join {
   183  	var x selectStmt
   184  	f(&x)
   185  
   186  	var b buffer
   187  	b.push(paren(x.make()))
   188  	if as != "" {
   189  		b.push(as)
   190  	}
   191  
   192  	j := join{
   193  		typ:   typ,
   194  		table: &b,
   195  	}
   196  	st.joins.push(&j)
   197  	return &j
   198  }
   199  
   200  func (st *selectStmt) JoinSelect(f func(b SelectStatement), as string) Join {
   201  	return st.joinSelect("join", f, as)
   202  }
   203  
   204  func (st *selectStmt) InnerJoinSelect(f func(b SelectStatement), as string) Join {
   205  	return st.joinSelect("inner join", f, as)
   206  }
   207  
   208  func (st *selectStmt) FullOuterJoinSelect(f func(b SelectStatement), as string) Join {
   209  	return st.joinSelect("full outer join", f, as)
   210  }
   211  
   212  func (st *selectStmt) LeftJoinSelect(f func(b SelectStatement), as string) Join {
   213  	return st.joinSelect("left join", f, as)
   214  }
   215  
   216  func (st *selectStmt) RightJoinSelect(f func(b SelectStatement), as string) Join {
   217  	return st.joinSelect("right join", f, as)
   218  }
   219  
   220  func (st *selectStmt) JoinLateralSelect(f func(b SelectStatement), as string) Join {
   221  	return st.joinSelect("join lateral", f, as)
   222  }
   223  
   224  func (st *selectStmt) InnerJoinLateralSelect(f func(b SelectStatement), as string) Join {
   225  	return st.joinSelect("inner join lateral", f, as)
   226  }
   227  
   228  func (st *selectStmt) FullOuterJoinLateralSelect(f func(b SelectStatement), as string) Join {
   229  	return st.joinSelect("full outer join lateral", f, as)
   230  }
   231  
   232  func (st *selectStmt) LeftJoinLateralSelect(f func(b SelectStatement), as string) Join {
   233  	return st.joinSelect("left join lateral", f, as)
   234  }
   235  
   236  func (st *selectStmt) RightJoinLateralSelect(f func(b SelectStatement), as string) Join {
   237  	return st.joinSelect("right join lateral", f, as)
   238  }
   239  
   240  func (st *selectStmt) joinUnion(typ string, f func(b UnionStatement), as string) Join {
   241  	var x unionStmt
   242  	f(&x)
   243  
   244  	var b buffer
   245  	b.push(paren(x.make()))
   246  	if as != "" {
   247  		b.push(as)
   248  	}
   249  
   250  	j := join{
   251  		typ:   typ,
   252  		table: &b,
   253  	}
   254  	st.joins.push(&j)
   255  	return &j
   256  }
   257  
   258  func (st *selectStmt) JoinUnion(f func(b UnionStatement), as string) Join {
   259  	return st.joinUnion("join", f, as)
   260  }
   261  
   262  func (st *selectStmt) InnerJoinUnion(f func(b UnionStatement), as string) Join {
   263  	return st.joinUnion("inner join", f, as)
   264  }
   265  
   266  func (st *selectStmt) FullOuterJoinUnion(f func(b UnionStatement), as string) Join {
   267  	return st.joinUnion("full outer join", f, as)
   268  }
   269  
   270  func (st *selectStmt) LeftJoinUnion(f func(b UnionStatement), as string) Join {
   271  	return st.joinUnion("left join", f, as)
   272  }
   273  
   274  func (st *selectStmt) RightJoinUnion(f func(b UnionStatement), as string) Join {
   275  	return st.joinUnion("right join", f, as)
   276  }
   277  
   278  func (st *selectStmt) Where(f func(b Cond)) {
   279  	f(&st.where)
   280  }
   281  
   282  func (st *selectStmt) GroupBy(col ...string) {
   283  	st.groupBy.pushString(col...)
   284  }
   285  
   286  func (st *selectStmt) Having(f func(b Cond)) {
   287  	f(&st.having)
   288  }
   289  
   290  func (st *selectStmt) OrderBy(col string) OrderBy {
   291  	p := orderBy{
   292  		col: col,
   293  	}
   294  	st.orderBy.push(&p)
   295  	return &p
   296  }
   297  
   298  func (st *selectStmt) Limit(n int64) {
   299  	st.limit = &n
   300  }
   301  
   302  func (st *selectStmt) Offset(n int64) {
   303  	st.offset = &n
   304  }
   305  
   306  func (st *selectStmt) make() *buffer {
   307  	var b buffer
   308  	b.push("select")
   309  	if st.distinct != nil {
   310  		b.push("distinct")
   311  
   312  		if !st.distinct.columns.empty() {
   313  			b.push("on")
   314  			b.push(&st.distinct.columns)
   315  		}
   316  	}
   317  	if !st.columns.empty() {
   318  		b.push(&st.columns)
   319  	}
   320  	if !st.from.empty() {
   321  		st.from.sep = ", "
   322  		b.push("from", &st.from)
   323  
   324  		if !st.joins.empty() {
   325  			b.push(st.joins.q...)
   326  		}
   327  	}
   328  	if !st.where.empty() {
   329  		b.push("where", &st.where)
   330  	}
   331  	if !st.groupBy.empty() {
   332  		b.push("group by", paren(&st.groupBy))
   333  	}
   334  	if !st.having.empty() {
   335  		b.push("having", &st.having)
   336  	}
   337  	if !st.orderBy.empty() {
   338  		b.push("order by", &st.orderBy)
   339  	}
   340  	if st.limit != nil {
   341  		b.push("limit", *st.limit)
   342  	}
   343  	if st.offset != nil {
   344  		b.push("offset", *st.offset)
   345  	}
   346  
   347  	return &b
   348  }
   349  
   350  type join struct {
   351  	typ   string // join, inner join, full outer join, left join, right join
   352  	table builder
   353  	using group
   354  	on    cond
   355  }
   356  
   357  func (st *join) On(f func(b Cond)) {
   358  	f(&st.on)
   359  }
   360  
   361  func (st *join) Using(col ...string) {
   362  	st.using.push(parenString(col...))
   363  }
   364  
   365  func (st *join) build() []any {
   366  	var b buffer
   367  	b.push(st.typ, st.table)
   368  	if !st.using.empty() {
   369  		b.push("using")
   370  		b.push(&st.using)
   371  	}
   372  	if !st.on.empty() {
   373  		b.push("on", &st.on)
   374  	}
   375  	return b.q
   376  }
   377  
   378  type orderBy struct {
   379  	col       string
   380  	direction string
   381  	nulls     string
   382  }
   383  
   384  func (st *orderBy) Asc() OrderBy {
   385  	st.direction = "asc"
   386  	return st
   387  }
   388  
   389  func (st *orderBy) Desc() OrderBy {
   390  	st.direction = "desc"
   391  	return st
   392  }
   393  
   394  func (st *orderBy) NullsFirst() OrderBy {
   395  	st.nulls = "first"
   396  	return st
   397  }
   398  
   399  func (st *orderBy) NullsLast() OrderBy {
   400  	st.nulls = "last"
   401  	return st
   402  }
   403  
   404  func (st *orderBy) build() []any {
   405  	var b buffer
   406  	b.push(st.col)
   407  	if st.direction != "" {
   408  		b.push(st.direction)
   409  	}
   410  	if st.nulls != "" {
   411  		b.push("nulls", st.nulls)
   412  	}
   413  	return b.q
   414  }
   415  
   416  type values struct {
   417  	group
   418  }
   419  
   420  func (st *values) Value(value ...any) {
   421  	var x parenGroup
   422  	for _, v := range value {
   423  		x.push(Arg(v))
   424  	}
   425  	st.push(&x)
   426  }
   427  
   428  func (st *values) Values(values ...[]any) {
   429  	for _, value := range values {
   430  		st.Value(value...)
   431  	}
   432  }
   433  
   434  type distinct struct {
   435  	columns parenGroup
   436  }
   437  
   438  func (st *distinct) On(col ...string) {
   439  	st.columns.pushString(col...)
   440  }