package sqlite import ( "context" "database/sql" "encoding/json" "errors" "time" "github.com/golang-migrate/migrate/v4" "github.com/huandu/go-sqlbuilder" "github.com/sagernet/sing-box/common/byteformats" "github.com/sagernet/sing-box/service/manager/constant" _ "modernc.org/sqlite" ) var squadFilters, nodeFilters, userFilters, bandwidthLimiterFilters, connectionLimiterFilters, trafficLimiterFilters, rateLimiterFilters map[string]Filter type SQLiteRepository struct { db *sql.DB ctx context.Context } func NewSQLiteRepository(ctx context.Context, dsn string) (*SQLiteRepository, error) { db, err := sql.Open("sqlite", dsn) if err != nil { return nil, err } if err := Migrate(db); err != nil && err != migrate.ErrNoChange { db.Close() return nil, err } return &SQLiteRepository{db: db, ctx: ctx}, nil } func (r *SQLiteRepository) CreateSquad(squad constant.SquadCreate) (constant.Squad, error) { var s constant.Squad now := time.Now() err := r.db.QueryRowContext( r.ctx, ` INSERT INTO squads ( name, created_at, updated_at ) VALUES (?, ?, ?) RETURNING id, name, created_at, updated_at `, squad.Name, now, now, ).Scan( &s.ID, &s.Name, &s.CreatedAt, &s.UpdatedAt, ) return s, err } func (r *SQLiteRepository) GetSquads(filters map[string][]string) ([]constant.Squad, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select( "id", "name", "created_at", "updated_at", ). From("squads") for k, v := range filters { if f, ok := squadFilters[k]; ok { if err := f(sb, v); err != nil { return nil, err } } } query, args := sb.Build() rows, err := r.db.QueryContext(r.ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var result []constant.Squad for rows.Next() { var squad constant.Squad if err := rows.Scan( &squad.ID, &squad.Name, &squad.CreatedAt, &squad.UpdatedAt, ); err != nil { return nil, err } result = append(result, squad) } return result, rows.Err() } func (r *SQLiteRepository) GetSquadsCount(filters map[string][]string) (int, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select("COUNT(*)"). From("squads") for k, v := range filters { if f, ok := squadFilters[k]; ok { if err := f(sb, v); err != nil { return 0, err } } } query, args := sb.Build() var count int err := r.db.QueryRowContext(r.ctx, query, args...).Scan(&count) return count, err } func (r *SQLiteRepository) GetSquad(id int) (constant.Squad, error) { var s constant.Squad err := r.db.QueryRowContext(r.ctx, ` SELECT id, name, created_at, updated_at FROM squads WHERE id=? `, id).Scan( &s.ID, &s.Name, &s.CreatedAt, &s.UpdatedAt, ) return s, err } func (r *SQLiteRepository) UpdateSquad(id int, squad constant.SquadUpdate) (constant.Squad, error) { var s constant.Squad err := r.db.QueryRowContext( r.ctx, ` UPDATE squads SET name=?, updated_at=? WHERE id=? RETURNING id, name, created_at, updated_at `, squad.Name, time.Now(), id, ).Scan( &s.ID, &s.Name, &s.CreatedAt, &s.UpdatedAt, ) return s, err } func (r *SQLiteRepository) DeleteSquad(id int) (constant.DeletedSquad, error) { var result constant.DeletedSquad tx, err := r.db.BeginTx(r.ctx, nil) if err != nil { return result, err } defer tx.Rollback() affectedNodeRows, err := tx.QueryContext(r.ctx, `DELETE FROM node_to_squad WHERE squad_id=? RETURNING node_uuid`, id) if err != nil { return result, err } affectedNodeUUIDs := make([]string, 0) for affectedNodeRows.Next() { var uuid string if err = affectedNodeRows.Scan(&uuid); err != nil { affectedNodeRows.Close() return result, err } affectedNodeUUIDs = append(affectedNodeUUIDs, uuid) } affectedNodeRows.Close() if err = affectedNodeRows.Err(); err != nil { return result, err } for _, table := range []string{ "user_to_squad", "connection_limiter_to_squad", "bandwidth_limiter_to_squad", "traffic_limiter_to_squad", "rate_limiter_to_squad", } { if _, err = tx.ExecContext(r.ctx, `DELETE FROM `+table+` WHERE squad_id=?`, id); err != nil { return result, err } } err = tx.QueryRowContext(r.ctx, ` DELETE FROM squads WHERE id=? RETURNING id, name, created_at, updated_at `, id).Scan( &result.Squad.ID, &result.Squad.Name, &result.Squad.CreatedAt, &result.Squad.UpdatedAt, ) if err != nil { return result, err } orphanedNodeRows, err := tx.QueryContext(r.ctx, ` DELETE FROM nodes WHERE NOT EXISTS (SELECT 1 FROM node_to_squad WHERE node_to_squad.node_uuid = nodes.uuid) RETURNING uuid `) if err != nil { return result, err } orphanedNodeUUIDs := make(map[string]struct{}) for orphanedNodeRows.Next() { var uuid string if err = orphanedNodeRows.Scan(&uuid); err != nil { orphanedNodeRows.Close() return result, err } orphanedNodeUUIDs[uuid] = struct{}{} result.OrphanedNodeUUIDs = append(result.OrphanedNodeUUIDs, uuid) } orphanedNodeRows.Close() if err = orphanedNodeRows.Err(); err != nil { return result, err } for _, uuid := range affectedNodeUUIDs { if _, ok := orphanedNodeUUIDs[uuid]; !ok { result.SurvivingNodeUUIDs = append(result.SurvivingNodeUUIDs, uuid) } } if _, err = tx.ExecContext(r.ctx, ` DELETE FROM users WHERE NOT EXISTS (SELECT 1 FROM user_to_squad WHERE user_to_squad.user_id = users.id) `); err != nil { return result, err } connRows, err := tx.QueryContext(r.ctx, ` DELETE FROM connection_limiters WHERE NOT EXISTS (SELECT 1 FROM connection_limiter_to_squad WHERE connection_limiter_to_squad.connection_limiter_id = connection_limiters.id) RETURNING id `) if err != nil { return result, err } for connRows.Next() { var lid int if err = connRows.Scan(&lid); err != nil { connRows.Close() return result, err } result.OrphanedConnectionLimiterIDs = append(result.OrphanedConnectionLimiterIDs, lid) } connRows.Close() if err = connRows.Err(); err != nil { return result, err } if _, err = tx.ExecContext(r.ctx, ` DELETE FROM bandwidth_limiters WHERE NOT EXISTS (SELECT 1 FROM bandwidth_limiter_to_squad WHERE bandwidth_limiter_to_squad.bandwidth_limiter_id = bandwidth_limiters.id) `); err != nil { return result, err } trafficRows, err := tx.QueryContext(r.ctx, ` DELETE FROM traffic_limiters WHERE NOT EXISTS (SELECT 1 FROM traffic_limiter_to_squad WHERE traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id) RETURNING id `) if err != nil { return result, err } for trafficRows.Next() { var lid int if err = trafficRows.Scan(&lid); err != nil { trafficRows.Close() return result, err } result.OrphanedTrafficLimiterIDs = append(result.OrphanedTrafficLimiterIDs, lid) } trafficRows.Close() if err = trafficRows.Err(); err != nil { return result, err } if _, err = tx.ExecContext(r.ctx, ` DELETE FROM rate_limiters WHERE NOT EXISTS (SELECT 1 FROM rate_limiter_to_squad WHERE rate_limiter_to_squad.rate_limiter_id = rate_limiters.id) `); err != nil { return result, err } if err = tx.Commit(); err != nil { return result, err } return result, nil } func (r *SQLiteRepository) CreateNode(node constant.NodeCreate) (constant.Node, error) { var n constant.Node tx, err := r.db.BeginTx(r.ctx, nil) if err != nil { return n, err } defer tx.Rollback() now := time.Now() err = tx.QueryRowContext( r.ctx, ` INSERT INTO nodes ( uuid, name, created_at, updated_at ) VALUES (?, ?, ?, ?) RETURNING uuid, name, created_at, updated_at `, node.UUID, node.Name, now, now, ).Scan( &n.UUID, &n.Name, &n.CreatedAt, &n.UpdatedAt, ) if err != nil { return n, err } stmt, err := tx.PrepareContext(r.ctx, `INSERT INTO node_to_squad (node_uuid, squad_id) VALUES (?, ?)`) if err != nil { return n, err } defer stmt.Close() for _, squadID := range node.SquadIDs { if _, err = stmt.ExecContext(r.ctx, node.UUID, squadID); err != nil { return n, err } } if err = tx.Commit(); err != nil { return n, err } n.SquadIDs = node.SquadIDs return n, nil } func (r *SQLiteRepository) GetNodes(filters map[string][]string) ([]constant.Node, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select( "uuid", "name", `( SELECT json_group_array(squad_id) FROM node_to_squad WHERE node_to_squad.node_uuid = nodes.uuid ) as squad_ids`, "created_at", "updated_at", ). From("nodes") for key, value := range filters { if filter, ok := nodeFilters[key]; ok { if err := filter(sb, value); err != nil { return nil, err } } } query, args := sb.Build() rows, err := r.db.QueryContext(r.ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var result []constant.Node for rows.Next() { var n constant.Node var squadIDs intSliceJSON if err := rows.Scan( &n.UUID, &n.Name, &squadIDs, &n.CreatedAt, &n.UpdatedAt, ); err != nil { return nil, err } n.SquadIDs = []int(squadIDs) result = append(result, n) } return result, rows.Err() } func (r *SQLiteRepository) GetNodesCount(filters map[string][]string) (int, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select("COUNT(*)"). From("nodes") for key, value := range filters { if filter, ok := nodeFilters[key]; ok { if err := filter(sb, value); err != nil { return 0, err } } } query, args := sb.Build() var count int err := r.db.QueryRowContext(r.ctx, query, args...).Scan(&count) return count, err } func (r *SQLiteRepository) GetNode(uuid string) (constant.Node, error) { var n constant.Node var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` SELECT uuid, name, ( SELECT json_group_array(squad_id) FROM node_to_squad WHERE node_to_squad.node_uuid = nodes.uuid ) as squad_ids, created_at, updated_at FROM nodes WHERE uuid = ? `, uuid).Scan( &n.UUID, &n.Name, &squadIDs, &n.CreatedAt, &n.UpdatedAt, ) if errors.Is(err, sql.ErrNoRows) { return n, constant.ErrNotFound } n.SquadIDs = []int(squadIDs) return n, err } func (r *SQLiteRepository) UpdateNode(uuid string, node constant.NodeUpdate) (constant.Node, error) { var n constant.Node err := r.db.QueryRowContext( r.ctx, ` UPDATE nodes SET name = ?, updated_at = ? WHERE uuid = ? RETURNING uuid, name, created_at, updated_at `, node.Name, time.Now(), uuid, ).Scan( &n.UUID, &n.Name, &n.CreatedAt, &n.UpdatedAt, ) return n, err } func (r *SQLiteRepository) DeleteNode(uuid string) (constant.Node, error) { var n constant.Node err := r.db.QueryRowContext(r.ctx, ` DELETE FROM nodes WHERE uuid = ? RETURNING uuid, name, created_at, updated_at `, uuid).Scan( &n.UUID, &n.Name, &n.CreatedAt, &n.UpdatedAt, ) return n, err } func (r *SQLiteRepository) CreateUser(user constant.UserCreate) (constant.User, error) { var u constant.User tx, err := r.db.BeginTx(r.ctx, nil) if err != nil { return u, err } defer tx.Rollback() now := time.Now() err = tx.QueryRowContext( r.ctx, ` INSERT INTO users ( username, inbound, type, uuid, password, secret, flow, alter_id, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING id, username, inbound, type, uuid, password, secret, flow, alter_id, created_at, updated_at `, user.Username, user.Inbound, user.Type, user.UUID, user.Password, user.Secret, user.Flow, user.AlterID, now, now, ).Scan( &u.ID, &u.Username, &u.Inbound, &u.Type, &u.UUID, &u.Password, &u.Secret, &u.Flow, &u.AlterID, &u.CreatedAt, &u.UpdatedAt, ) if err != nil { return u, err } stmt, err := tx.PrepareContext(r.ctx, `INSERT INTO user_to_squad (user_id, squad_id) VALUES (?, ?)`) if err != nil { return u, err } defer stmt.Close() for _, squadID := range user.SquadIDs { if _, err = stmt.ExecContext(r.ctx, u.ID, squadID); err != nil { return u, err } } if err = tx.Commit(); err != nil { return u, err } u.SquadIDs = user.SquadIDs return u, nil } func (r *SQLiteRepository) GetUsers(filters map[string][]string) ([]constant.User, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select( "id", `( SELECT json_group_array(squad_id) FROM user_to_squad WHERE user_to_squad.user_id = users.id ) as squad_ids`, "username", "inbound", "type", "uuid", "password", "secret", "flow", "alter_id", "created_at", "updated_at", ). From("users") for key, value := range filters { if filter, ok := userFilters[key]; ok { if err := filter(sb, value); err != nil { return nil, err } } } query, args := sb.Build() rows, err := r.db.QueryContext(r.ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var result []constant.User for rows.Next() { var u constant.User var squadIDs intSliceJSON if err := rows.Scan( &u.ID, &squadIDs, &u.Username, &u.Inbound, &u.Type, &u.UUID, &u.Password, &u.Secret, &u.Flow, &u.AlterID, &u.CreatedAt, &u.UpdatedAt, ); err != nil { return nil, err } u.SquadIDs = []int(squadIDs) result = append(result, u) } return result, rows.Err() } func (r *SQLiteRepository) GetUsersCount(filters map[string][]string) (int, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select("COUNT(*)"). From("users") for key, value := range filters { if filter, ok := userFilters[key]; ok { if err := filter(sb, value); err != nil { return 0, err } } } query, args := sb.Build() var count int err := r.db.QueryRowContext(r.ctx, query, args...).Scan(&count) return count, err } func (r *SQLiteRepository) GetUser(id int) (constant.User, error) { var u constant.User var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` SELECT id, ( SELECT json_group_array(squad_id) FROM user_to_squad WHERE user_to_squad.user_id = users.id ) as squad_ids, username, inbound, type, uuid, password, secret, flow, alter_id, created_at, updated_at FROM users WHERE id = ? `, id).Scan( &u.ID, &squadIDs, &u.Username, &u.Inbound, &u.Type, &u.UUID, &u.Password, &u.Secret, &u.Flow, &u.AlterID, &u.CreatedAt, &u.UpdatedAt, ) u.SquadIDs = []int(squadIDs) return u, err } func (r *SQLiteRepository) UpdateUser(id int, user constant.UserUpdate) (constant.User, error) { var u constant.User var squadIDs intSliceJSON err := r.db.QueryRowContext( r.ctx, ` UPDATE users SET uuid = ?, password = ?, secret = ?, flow = ?, alter_id = ?, updated_at = ? WHERE id = ? RETURNING id, ( SELECT json_group_array(squad_id) FROM user_to_squad WHERE user_to_squad.user_id = users.id ) as squad_ids, username, inbound, type, uuid, password, secret, flow, alter_id, created_at, updated_at `, user.UUID, user.Password, user.Secret, user.Flow, user.AlterID, time.Now(), id, ).Scan( &u.ID, &squadIDs, &u.Username, &u.Inbound, &u.Type, &u.UUID, &u.Password, &u.Secret, &u.Flow, &u.AlterID, &u.CreatedAt, &u.UpdatedAt, ) u.SquadIDs = []int(squadIDs) return u, err } func (r *SQLiteRepository) DeleteUser(id int) (constant.User, error) { var u constant.User var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` DELETE FROM users WHERE id = ? RETURNING id, ( SELECT json_group_array(squad_id) FROM user_to_squad WHERE user_to_squad.user_id = users.id ) as squad_ids, username, inbound, type, uuid, password, secret, flow, alter_id, created_at, updated_at `, id).Scan( &u.ID, &squadIDs, &u.Username, &u.Inbound, &u.Type, &u.UUID, &u.Password, &u.Secret, &u.Flow, &u.AlterID, &u.CreatedAt, &u.UpdatedAt, ) u.SquadIDs = []int(squadIDs) return u, err } func (r *SQLiteRepository) CreateConnectionLimiter(limiter constant.ConnectionLimiterCreate) (constant.ConnectionLimiter, error) { var cl constant.ConnectionLimiter tx, err := r.db.BeginTx(r.ctx, nil) if err != nil { return cl, err } defer tx.Rollback() now := time.Now() err = tx.QueryRowContext( r.ctx, ` INSERT INTO connection_limiters ( username, outbound, strategy, connection_type, lock_type, count, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id, username, outbound, strategy, connection_type, lock_type, count, created_at, updated_at `, limiter.Username, limiter.Outbound, limiter.Strategy, limiter.ConnectionType, limiter.LockType, limiter.Count, now, now, ).Scan( &cl.ID, &cl.Username, &cl.Outbound, &cl.Strategy, &cl.ConnectionType, &cl.LockType, &cl.Count, &cl.CreatedAt, &cl.UpdatedAt, ) if err != nil { return cl, err } stmt, err := tx.PrepareContext(r.ctx, `INSERT INTO connection_limiter_to_squad (connection_limiter_id, squad_id) VALUES (?, ?)`) if err != nil { return cl, err } defer stmt.Close() for _, squadID := range limiter.SquadIDs { if _, err = stmt.ExecContext(r.ctx, cl.ID, squadID); err != nil { return cl, err } } if err = tx.Commit(); err != nil { return cl, err } cl.SquadIDs = limiter.SquadIDs return cl, nil } func (r *SQLiteRepository) GetConnectionLimiters(filters map[string][]string) ([]constant.ConnectionLimiter, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select( "id", `( SELECT json_group_array(squad_id) FROM connection_limiter_to_squad WHERE connection_limiter_to_squad.connection_limiter_id = connection_limiters.id ) as squad_ids`, "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at", ). From("connection_limiters") for k, v := range filters { if f, ok := connectionLimiterFilters[k]; ok { if err := f(sb, v); err != nil { return nil, err } } } query, args := sb.Build() rows, err := r.db.QueryContext(r.ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var result []constant.ConnectionLimiter for rows.Next() { var cl constant.ConnectionLimiter var squadIDs intSliceJSON if err := rows.Scan( &cl.ID, &squadIDs, &cl.Username, &cl.Outbound, &cl.Strategy, &cl.ConnectionType, &cl.LockType, &cl.Count, &cl.CreatedAt, &cl.UpdatedAt, ); err != nil { return nil, err } cl.SquadIDs = []int(squadIDs) result = append(result, cl) } return result, rows.Err() } func (r *SQLiteRepository) GetConnectionLimitersCount(filters map[string][]string) (int, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select("COUNT(*)"). From("connection_limiters") for k, v := range filters { if f, ok := connectionLimiterFilters[k]; ok { if err := f(sb, v); err != nil { return 0, err } } } query, args := sb.Build() var count int err := r.db.QueryRowContext(r.ctx, query, args...).Scan(&count) return count, err } func (r *SQLiteRepository) GetConnectionLimiter(id int) (constant.ConnectionLimiter, error) { var cl constant.ConnectionLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` SELECT id, ( SELECT json_group_array(squad_id) FROM connection_limiter_to_squad WHERE connection_limiter_to_squad.connection_limiter_id = connection_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, lock_type, count, created_at, updated_at FROM connection_limiters WHERE id=? `, id).Scan( &cl.ID, &squadIDs, &cl.Username, &cl.Outbound, &cl.Strategy, &cl.ConnectionType, &cl.LockType, &cl.Count, &cl.CreatedAt, &cl.UpdatedAt, ) cl.SquadIDs = []int(squadIDs) return cl, err } func (r *SQLiteRepository) UpdateConnectionLimiter(id int, limiter constant.ConnectionLimiterUpdate) (constant.ConnectionLimiter, error) { var cl constant.ConnectionLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext( r.ctx, ` UPDATE connection_limiters SET strategy=?, connection_type=?, lock_type=?, count=?, updated_at=? WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM connection_limiter_to_squad WHERE connection_limiter_to_squad.connection_limiter_id = connection_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, lock_type, count, created_at, updated_at `, limiter.Strategy, limiter.ConnectionType, limiter.LockType, limiter.Count, time.Now(), id, ).Scan( &cl.ID, &squadIDs, &cl.Username, &cl.Outbound, &cl.Strategy, &cl.ConnectionType, &cl.LockType, &cl.Count, &cl.CreatedAt, &cl.UpdatedAt, ) cl.SquadIDs = []int(squadIDs) return cl, err } func (r *SQLiteRepository) DeleteConnectionLimiter(id int) (constant.ConnectionLimiter, error) { var cl constant.ConnectionLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` DELETE FROM connection_limiters WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM connection_limiter_to_squad WHERE connection_limiter_to_squad.connection_limiter_id = connection_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, lock_type, count, created_at, updated_at `, id).Scan( &cl.ID, &squadIDs, &cl.Username, &cl.Outbound, &cl.Strategy, &cl.ConnectionType, &cl.LockType, &cl.Count, &cl.CreatedAt, &cl.UpdatedAt, ) cl.SquadIDs = []int(squadIDs) return cl, err } func (r *SQLiteRepository) CreateBandwidthLimiter(limiter constant.BandwidthLimiterCreate) (constant.BandwidthLimiter, error) { var bl constant.BandwidthLimiter tx, err := r.db.BeginTx(r.ctx, nil) if err != nil { return bl, err } defer tx.Rollback() bytesSpeed, err := json.Marshal(limiter.Speed) if err != nil { return bl, err } raw := &byteformats.NetworkBytesCompat{} if err = raw.UnmarshalJSON(bytesSpeed); err != nil { return bl, err } flowKeysJSON, err := marshalStringSlice(limiter.FlowKeys) if err != nil { return bl, err } var flowKeys stringSliceJSON now := time.Now() err = tx.QueryRowContext( r.ctx, ` INSERT INTO bandwidth_limiters ( username, outbound, strategy, connection_type, mode, flow_keys, speed, raw_speed, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING id, username, outbound, strategy, connection_type, mode, flow_keys, speed, raw_speed, created_at, updated_at `, limiter.Username, limiter.Outbound, limiter.Strategy, limiter.ConnectionType, limiter.Mode, flowKeysJSON, limiter.Speed, raw.Value(), now, now, ).Scan( &bl.ID, &bl.Username, &bl.Outbound, &bl.Strategy, &bl.ConnectionType, &bl.Mode, &flowKeys, &bl.Speed, &bl.RawSpeed, &bl.CreatedAt, &bl.UpdatedAt, ) if err != nil { return bl, err } bl.FlowKeys = []string(flowKeys) stmt, err := tx.PrepareContext(r.ctx, `INSERT INTO bandwidth_limiter_to_squad (bandwidth_limiter_id, squad_id) VALUES (?, ?)`) if err != nil { return bl, err } defer stmt.Close() for _, squadID := range limiter.SquadIDs { if _, err = stmt.ExecContext(r.ctx, bl.ID, squadID); err != nil { return bl, err } } if err = tx.Commit(); err != nil { return bl, err } bl.SquadIDs = limiter.SquadIDs return bl, nil } func (r *SQLiteRepository) GetBandwidthLimiters(filters map[string][]string) ([]constant.BandwidthLimiter, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select( "id", `( SELECT json_group_array(squad_id) FROM bandwidth_limiter_to_squad WHERE bandwidth_limiter_to_squad.bandwidth_limiter_id = bandwidth_limiters.id ) as squad_ids`, "username", "outbound", "strategy", "connection_type", "mode", "flow_keys", "speed", "raw_speed", "created_at", "updated_at", ). From("bandwidth_limiters") for k, v := range filters { if f, ok := bandwidthLimiterFilters[k]; ok { if err := f(sb, v); err != nil { return nil, err } } } query, args := sb.Build() rows, err := r.db.QueryContext(r.ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var result []constant.BandwidthLimiter for rows.Next() { var bl constant.BandwidthLimiter var squadIDs intSliceJSON var flowKeys stringSliceJSON if err := rows.Scan( &bl.ID, &squadIDs, &bl.Username, &bl.Outbound, &bl.Strategy, &bl.ConnectionType, &bl.Mode, &flowKeys, &bl.Speed, &bl.RawSpeed, &bl.CreatedAt, &bl.UpdatedAt, ); err != nil { return nil, err } bl.SquadIDs = []int(squadIDs) bl.FlowKeys = []string(flowKeys) result = append(result, bl) } return result, rows.Err() } func (r *SQLiteRepository) GetBandwidthLimitersCount(filters map[string][]string) (int, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select("COUNT(*)"). From("bandwidth_limiters") for k, v := range filters { if f, ok := bandwidthLimiterFilters[k]; ok { if err := f(sb, v); err != nil { return 0, err } } } query, args := sb.Build() var count int err := r.db.QueryRowContext(r.ctx, query, args...).Scan(&count) return count, err } func (r *SQLiteRepository) GetBandwidthLimiter(id int) (constant.BandwidthLimiter, error) { var bl constant.BandwidthLimiter var squadIDs intSliceJSON var flowKeys stringSliceJSON err := r.db.QueryRowContext(r.ctx, ` SELECT id, ( SELECT json_group_array(squad_id) FROM bandwidth_limiter_to_squad WHERE bandwidth_limiter_to_squad.bandwidth_limiter_id = bandwidth_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, mode, flow_keys, speed, raw_speed, created_at, updated_at FROM bandwidth_limiters WHERE id=? `, id).Scan( &bl.ID, &squadIDs, &bl.Username, &bl.Outbound, &bl.Strategy, &bl.ConnectionType, &bl.Mode, &flowKeys, &bl.Speed, &bl.RawSpeed, &bl.CreatedAt, &bl.UpdatedAt, ) bl.SquadIDs = []int(squadIDs) bl.FlowKeys = []string(flowKeys) return bl, err } func (r *SQLiteRepository) UpdateBandwidthLimiter(id int, limiter constant.BandwidthLimiterUpdate) (constant.BandwidthLimiter, error) { var bl constant.BandwidthLimiter var squadIDs intSliceJSON var flowKeys stringSliceJSON bytesSpeed, err := json.Marshal(limiter.Speed) if err != nil { return bl, err } raw := &byteformats.NetworkBytesCompat{} if err = raw.UnmarshalJSON(bytesSpeed); err != nil { return bl, err } flowKeysJSON, err := marshalStringSlice(limiter.FlowKeys) if err != nil { return bl, err } err = r.db.QueryRowContext( r.ctx, ` UPDATE bandwidth_limiters SET username=?, outbound=?, strategy=?, connection_type=?, mode=?, flow_keys=?, speed=?, raw_speed=?, updated_at=? WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM bandwidth_limiter_to_squad WHERE bandwidth_limiter_to_squad.bandwidth_limiter_id = bandwidth_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, mode, flow_keys, speed, raw_speed, created_at, updated_at `, limiter.Username, limiter.Outbound, limiter.Strategy, limiter.ConnectionType, limiter.Mode, flowKeysJSON, limiter.Speed, raw.Value(), time.Now(), id, ).Scan( &bl.ID, &squadIDs, &bl.Username, &bl.Outbound, &bl.Strategy, &bl.ConnectionType, &bl.Mode, &flowKeys, &bl.Speed, &bl.RawSpeed, &bl.CreatedAt, &bl.UpdatedAt, ) bl.SquadIDs = []int(squadIDs) bl.FlowKeys = []string(flowKeys) return bl, err } func (r *SQLiteRepository) DeleteBandwidthLimiter(id int) (constant.BandwidthLimiter, error) { var bl constant.BandwidthLimiter var squadIDs intSliceJSON var flowKeys stringSliceJSON err := r.db.QueryRowContext(r.ctx, ` DELETE FROM bandwidth_limiters WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM bandwidth_limiter_to_squad WHERE bandwidth_limiter_to_squad.bandwidth_limiter_id = bandwidth_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, mode, flow_keys, speed, raw_speed, created_at, updated_at `, id).Scan( &bl.ID, &squadIDs, &bl.Username, &bl.Outbound, &bl.Strategy, &bl.ConnectionType, &bl.Mode, &flowKeys, &bl.Speed, &bl.RawSpeed, &bl.CreatedAt, &bl.UpdatedAt, ) bl.SquadIDs = []int(squadIDs) bl.FlowKeys = []string(flowKeys) return bl, err } func (r *SQLiteRepository) CreateTrafficLimiter(limiter constant.TrafficLimiterCreate) (constant.TrafficLimiter, error) { var tl constant.TrafficLimiter tx, err := r.db.BeginTx(r.ctx, nil) if err != nil { return tl, err } defer tx.Rollback() bytesQuota, err := json.Marshal(limiter.Quota) if err != nil { return tl, err } rawQuota := &byteformats.NetworkBytesCompat{} if err = rawQuota.UnmarshalJSON(bytesQuota); err != nil { return tl, err } now := time.Now() err = tx.QueryRowContext( r.ctx, ` INSERT INTO traffic_limiters ( username, outbound, strategy, mode, quota, raw_quota, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id, username, outbound, strategy, mode, raw_used, quota, raw_quota, CASE WHEN raw_quota = 0 THEN 0 ELSE min(100, CAST(raw_used * 100.0 / raw_quota AS INTEGER)) END AS usage, created_at, updated_at `, limiter.Username, limiter.Outbound, limiter.Strategy, limiter.Mode, limiter.Quota, rawQuota.Value(), now, now, ).Scan( &tl.ID, &tl.Username, &tl.Outbound, &tl.Strategy, &tl.Mode, &tl.RawUsed, &tl.Quota, &tl.RawQuota, &tl.Usage, &tl.CreatedAt, &tl.UpdatedAt, ) if err != nil { return tl, err } stmt, err := tx.PrepareContext(r.ctx, `INSERT INTO traffic_limiter_to_squad (traffic_limiter_id, squad_id) VALUES (?, ?)`) if err != nil { return tl, err } defer stmt.Close() for _, squadID := range limiter.SquadIDs { if _, err = stmt.ExecContext(r.ctx, tl.ID, squadID); err != nil { return tl, err } } if err = tx.Commit(); err != nil { return tl, err } tl.SquadIDs = limiter.SquadIDs return tl, nil } func (r *SQLiteRepository) GetTrafficLimiters(filters map[string][]string) ([]constant.TrafficLimiter, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select( "id", `( SELECT json_group_array(squad_id) FROM traffic_limiter_to_squad WHERE traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id ) as squad_ids`, "username", "outbound", "strategy", "mode", "raw_used", "quota", "raw_quota", "CASE WHEN raw_quota = 0 THEN 0 ELSE min(100, CAST(raw_used * 100.0 / raw_quota AS INTEGER)) END AS usage", "created_at", "updated_at", ). From("traffic_limiters") for k, v := range filters { if f, ok := trafficLimiterFilters[k]; ok { if err := f(sb, v); err != nil { return nil, err } } } query, args := sb.Build() rows, err := r.db.QueryContext(r.ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var result []constant.TrafficLimiter for rows.Next() { var tl constant.TrafficLimiter var squadIDs intSliceJSON if err := rows.Scan( &tl.ID, &squadIDs, &tl.Username, &tl.Outbound, &tl.Strategy, &tl.Mode, &tl.RawUsed, &tl.Quota, &tl.RawQuota, &tl.Usage, &tl.CreatedAt, &tl.UpdatedAt, ); err != nil { return nil, err } tl.SquadIDs = []int(squadIDs) result = append(result, tl) } return result, rows.Err() } func (r *SQLiteRepository) GetTrafficLimitersCount(filters map[string][]string) (int, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select("COUNT(*)"). From("traffic_limiters") for k, v := range filters { if f, ok := trafficLimiterFilters[k]; ok { if err := f(sb, v); err != nil { return 0, err } } } query, args := sb.Build() var count int err := r.db.QueryRowContext(r.ctx, query, args...).Scan(&count) return count, err } func (r *SQLiteRepository) GetTrafficLimiter(id int) (constant.TrafficLimiter, error) { var tl constant.TrafficLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` SELECT id, ( SELECT json_group_array(squad_id) FROM traffic_limiter_to_squad WHERE traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id ) as squad_ids, username, outbound, strategy, mode, raw_used, quota, raw_quota, CASE WHEN raw_quota = 0 THEN 0 ELSE min(100, CAST(raw_used * 100.0 / raw_quota AS INTEGER)) END AS usage, created_at, updated_at FROM traffic_limiters WHERE id=? `, id).Scan( &tl.ID, &squadIDs, &tl.Username, &tl.Outbound, &tl.Strategy, &tl.Mode, &tl.RawUsed, &tl.Quota, &tl.RawQuota, &tl.Usage, &tl.CreatedAt, &tl.UpdatedAt, ) tl.SquadIDs = []int(squadIDs) return tl, err } func (r *SQLiteRepository) UpdateTrafficLimiter(id int, limiter constant.TrafficLimiterUpdate) (constant.TrafficLimiter, error) { var tl constant.TrafficLimiter var squadIDs intSliceJSON bytesQuota, err := json.Marshal(limiter.Quota) if err != nil { return tl, err } rawQuota := &byteformats.NetworkBytesCompat{} if err = rawQuota.UnmarshalJSON(bytesQuota); err != nil { return tl, err } err = r.db.QueryRowContext( r.ctx, ` UPDATE traffic_limiters SET username=?, outbound=?, strategy=?, mode=?, quota=?, raw_quota=?, updated_at=? WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM traffic_limiter_to_squad WHERE traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id ) as squad_ids, username, outbound, strategy, mode, raw_used, quota, raw_quota, CASE WHEN raw_quota = 0 THEN 0 ELSE min(100, CAST(raw_used * 100.0 / raw_quota AS INTEGER)) END AS usage, created_at, updated_at `, limiter.Username, limiter.Outbound, limiter.Strategy, limiter.Mode, limiter.Quota, rawQuota.Value(), time.Now(), id, ).Scan( &tl.ID, &squadIDs, &tl.Username, &tl.Outbound, &tl.Strategy, &tl.Mode, &tl.RawUsed, &tl.Quota, &tl.RawQuota, &tl.Usage, &tl.CreatedAt, &tl.UpdatedAt, ) tl.SquadIDs = []int(squadIDs) return tl, err } func (r *SQLiteRepository) UpdateTrafficLimiterUsed(id int, current uint64) (constant.TrafficLimiter, error) { var tl constant.TrafficLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext( r.ctx, ` UPDATE traffic_limiters SET raw_used=?, updated_at=? WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM traffic_limiter_to_squad WHERE traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id ) as squad_ids, username, outbound, strategy, mode, raw_used, quota, raw_quota, CASE WHEN raw_quota = 0 THEN 0 ELSE min(100, CAST(raw_used * 100.0 / raw_quota AS INTEGER)) END AS usage, created_at, updated_at `, current, time.Now(), id, ).Scan( &tl.ID, &squadIDs, &tl.Username, &tl.Outbound, &tl.Strategy, &tl.Mode, &tl.RawUsed, &tl.Quota, &tl.RawQuota, &tl.Usage, &tl.CreatedAt, &tl.UpdatedAt, ) tl.SquadIDs = []int(squadIDs) return tl, err } func (r *SQLiteRepository) DeleteTrafficLimiter(id int) (constant.TrafficLimiter, error) { var tl constant.TrafficLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` DELETE FROM traffic_limiters WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM traffic_limiter_to_squad WHERE traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id ) as squad_ids, username, outbound, strategy, mode, raw_used, quota, raw_quota, CASE WHEN raw_quota = 0 THEN 0 ELSE min(100, CAST(raw_used * 100.0 / raw_quota AS INTEGER)) END AS usage, created_at, updated_at `, id).Scan( &tl.ID, &squadIDs, &tl.Username, &tl.Outbound, &tl.Strategy, &tl.Mode, &tl.RawUsed, &tl.Quota, &tl.RawQuota, &tl.Usage, &tl.CreatedAt, &tl.UpdatedAt, ) tl.SquadIDs = []int(squadIDs) return tl, err } func (r *SQLiteRepository) CreateRateLimiter(limiter constant.RateLimiterCreate) (constant.RateLimiter, error) { var rl constant.RateLimiter tx, err := r.db.BeginTx(r.ctx, nil) if err != nil { return rl, err } defer tx.Rollback() now := time.Now() err = tx.QueryRowContext( r.ctx, ` INSERT INTO rate_limiters ( username, outbound, strategy, connection_type, count, interval, created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id, username, outbound, strategy, connection_type, count, interval, created_at, updated_at `, limiter.Username, limiter.Outbound, limiter.Strategy, limiter.ConnectionType, limiter.Count, limiter.Interval, now, now, ).Scan( &rl.ID, &rl.Username, &rl.Outbound, &rl.Strategy, &rl.ConnectionType, &rl.Count, &rl.Interval, &rl.CreatedAt, &rl.UpdatedAt, ) if err != nil { return rl, err } stmt, err := tx.PrepareContext(r.ctx, `INSERT INTO rate_limiter_to_squad (rate_limiter_id, squad_id) VALUES (?, ?)`) if err != nil { return rl, err } defer stmt.Close() for _, squadID := range limiter.SquadIDs { if _, err = stmt.ExecContext(r.ctx, rl.ID, squadID); err != nil { return rl, err } } if err = tx.Commit(); err != nil { return rl, err } rl.SquadIDs = limiter.SquadIDs return rl, nil } func (r *SQLiteRepository) GetRateLimiters(filters map[string][]string) ([]constant.RateLimiter, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select( "id", `( SELECT json_group_array(squad_id) FROM rate_limiter_to_squad WHERE rate_limiter_to_squad.rate_limiter_id = rate_limiters.id ) as squad_ids`, "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at", ). From("rate_limiters") for k, v := range filters { if f, ok := rateLimiterFilters[k]; ok { if err := f(sb, v); err != nil { return nil, err } } } query, args := sb.Build() rows, err := r.db.QueryContext(r.ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var result []constant.RateLimiter for rows.Next() { var rl constant.RateLimiter var squadIDs intSliceJSON if err := rows.Scan( &rl.ID, &squadIDs, &rl.Username, &rl.Outbound, &rl.Strategy, &rl.ConnectionType, &rl.Count, &rl.Interval, &rl.CreatedAt, &rl.UpdatedAt, ); err != nil { return nil, err } rl.SquadIDs = []int(squadIDs) result = append(result, rl) } return result, rows.Err() } func (r *SQLiteRepository) GetRateLimitersCount(filters map[string][]string) (int, error) { sb := sqlbuilder.SQLite.NewSelectBuilder(). Select("COUNT(*)"). From("rate_limiters") for k, v := range filters { if f, ok := rateLimiterFilters[k]; ok { if err := f(sb, v); err != nil { return 0, err } } } query, args := sb.Build() var count int err := r.db.QueryRowContext(r.ctx, query, args...).Scan(&count) return count, err } func (r *SQLiteRepository) GetRateLimiter(id int) (constant.RateLimiter, error) { var rl constant.RateLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` SELECT id, ( SELECT json_group_array(squad_id) FROM rate_limiter_to_squad WHERE rate_limiter_to_squad.rate_limiter_id = rate_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, count, interval, created_at, updated_at FROM rate_limiters WHERE id=? `, id).Scan( &rl.ID, &squadIDs, &rl.Username, &rl.Outbound, &rl.Strategy, &rl.ConnectionType, &rl.Count, &rl.Interval, &rl.CreatedAt, &rl.UpdatedAt, ) rl.SquadIDs = []int(squadIDs) return rl, err } func (r *SQLiteRepository) UpdateRateLimiter(id int, limiter constant.RateLimiterUpdate) (constant.RateLimiter, error) { var rl constant.RateLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext( r.ctx, ` UPDATE rate_limiters SET username=?, outbound=?, strategy=?, connection_type=?, count=?, interval=?, updated_at=? WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM rate_limiter_to_squad WHERE rate_limiter_to_squad.rate_limiter_id = rate_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, count, interval, created_at, updated_at `, limiter.Username, limiter.Outbound, limiter.Strategy, limiter.ConnectionType, limiter.Count, limiter.Interval, time.Now(), id, ).Scan( &rl.ID, &squadIDs, &rl.Username, &rl.Outbound, &rl.Strategy, &rl.ConnectionType, &rl.Count, &rl.Interval, &rl.CreatedAt, &rl.UpdatedAt, ) rl.SquadIDs = []int(squadIDs) return rl, err } func (r *SQLiteRepository) DeleteRateLimiter(id int) (constant.RateLimiter, error) { var rl constant.RateLimiter var squadIDs intSliceJSON err := r.db.QueryRowContext(r.ctx, ` DELETE FROM rate_limiters WHERE id=? RETURNING id, ( SELECT json_group_array(squad_id) FROM rate_limiter_to_squad WHERE rate_limiter_to_squad.rate_limiter_id = rate_limiters.id ) as squad_ids, username, outbound, strategy, connection_type, count, interval, created_at, updated_at `, id).Scan( &rl.ID, &squadIDs, &rl.Username, &rl.Outbound, &rl.Strategy, &rl.ConnectionType, &rl.Count, &rl.Interval, &rl.CreatedAt, &rl.UpdatedAt, ) rl.SquadIDs = []int(squadIDs) return rl, err } func init() { squadFilters = map[string]Filter{ "id": EqualFilter("id"), "id_in": InFilter("id"), "pk": EqualFilter("id"), "name": EqualFilter("name"), "created_at_start": GreaterThanFilter("created_at"), "created_at_end": LessThanFilter("created_at"), "updated_at_start": GreaterThanFilter("updated_at"), "updated_at_end": LessThanFilter("updated_at"), "sort_asc": SortAscFilter(), "sort_desc": SortDescFilter(), "offset": OffsetFilter(), "limit": LimitFilter(), } nodeFilters = map[string]Filter{ "uuid": EqualFilter("uuid"), "pk": EqualFilter("uuid"), "name": EqualFilter("name"), "squad_id_in": ExistsAndWhereInFilter( sqlbuilder.SQLite.NewSelectBuilder(). Select( "squad_id", ). Where( "node_to_squad.node_uuid = nodes.uuid", ). From( "node_to_squad", ), "node_to_squad.squad_id", ), "created_at_start": GreaterThanFilter("created_at"), "created_at_end": LessThanFilter("created_at"), "updated_at_start": GreaterThanFilter("updated_at"), "updated_at_end": LessThanFilter("updated_at"), "sort_asc": SortAscFilter(), "sort_desc": SortDescFilter(), "offset": OffsetFilter(), "limit": LimitFilter(), } userFilters = map[string]Filter{ "id": EqualFilter("id"), "pk": EqualFilter("id"), "squad_id_in": ExistsAndWhereInFilter( sqlbuilder.SQLite.NewSelectBuilder(). Select( "squad_id", ). Where( "user_to_squad.user_id = users.id", ). From( "user_to_squad", ), "user_to_squad.squad_id", ), "username": EqualFilter("username"), "inbound": EqualFilter("inbound"), "type": EqualFilter("type"), "created_at_start": GreaterThanFilter("created_at"), "created_at_end": LessThanFilter("created_at"), "updated_at_start": GreaterThanFilter("updated_at"), "updated_at_end": LessThanFilter("updated_at"), "sort_asc": SortAscFilter(), "sort_desc": SortDescFilter(), "offset": OffsetFilter(), "limit": LimitFilter(), } connectionLimiterFilters = map[string]Filter{ "id": EqualFilter("id"), "pk": EqualFilter("id"), "squad_id_in": ExistsAndWhereInFilter( sqlbuilder.SQLite.NewSelectBuilder(). Select( "squad_id", ). Where( "connection_limiter_to_squad.connection_limiter_id = connection_limiters.id", ). From( "connection_limiter_to_squad", ), "connection_limiter_to_squad.squad_id", ), "strategy": EqualFilter("strategy"), "username": EqualFilter("username"), "outbound": EqualFilter("outbound"), "connection_type": EqualFilter("connection_type"), "lock_type": EqualFilter("lock_type"), "created_at_start": GreaterThanFilter("created_at"), "created_at_end": LessThanFilter("created_at"), "updated_at_start": GreaterThanFilter("updated_at"), "updated_at_end": LessThanFilter("updated_at"), "sort_asc": SortAscFilter(), "sort_desc": SortDescFilter(), "offset": OffsetFilter(), "limit": LimitFilter(), } bandwidthLimiterFilters = map[string]Filter{ "id": EqualFilter("id"), "pk": EqualFilter("id"), "squad_id_in": ExistsAndWhereInFilter( sqlbuilder.SQLite.NewSelectBuilder(). Select( "squad_id", ). Where( "bandwidth_limiter_to_squad.bandwidth_limiter_id = bandwidth_limiters.id", ). From( "bandwidth_limiter_to_squad", ), "bandwidth_limiter_to_squad.squad_id", ), "strategy": EqualFilter("strategy"), "mode": EqualFilter("mode"), "type": EqualFilter("type"), "username": EqualFilter("username"), "down_start": SpeedGreaterEqualThanFilter("raw_down"), "down_end": SpeedLessEqualThanFilter("raw_down"), "up_start": SpeedGreaterEqualThanFilter("raw_up"), "up_end": SpeedLessEqualThanFilter("raw_up"), "created_at_start": GreaterThanFilter("created_at"), "created_at_end": LessThanFilter("created_at"), "updated_at_start": GreaterThanFilter("updated_at"), "updated_at_end": LessThanFilter("updated_at"), "sort_asc": ReplacedSortAscFilter(map[string]string{"down": "raw_down", "up": "raw_up"}), "sort_desc": ReplacedSortDescFilter(map[string]string{"down": "raw_down", "up": "raw_up"}), "offset": OffsetFilter(), "limit": LimitFilter(), } trafficLimiterFilters = map[string]Filter{ "id": EqualFilter("id"), "pk": EqualFilter("id"), "squad_id_in": ExistsAndWhereInFilter( sqlbuilder.SQLite.NewSelectBuilder(). Select( "squad_id", ). Where( "traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id", ). From( "traffic_limiter_to_squad", ), "traffic_limiter_to_squad.squad_id", ), "username": EqualFilter("username"), "outbound": EqualFilter("outbound"), "strategy": EqualFilter("strategy"), "mode": EqualFilter("mode"), "used_start": SpeedGreaterEqualThanFilter("raw_used"), "used_end": SpeedLessEqualThanFilter("raw_used"), "quota_start": SpeedGreaterEqualThanFilter("raw_quota"), "quota_end": SpeedLessEqualThanFilter("raw_quota"), "created_at_start": GreaterThanFilter("created_at"), "created_at_end": LessThanFilter("created_at"), "updated_at_start": GreaterThanFilter("updated_at"), "updated_at_end": LessThanFilter("updated_at"), "sort_asc": ReplacedSortAscFilter(map[string]string{"used": "raw_used", "quota": "raw_quota"}), "sort_desc": ReplacedSortDescFilter(map[string]string{"used": "raw_used", "quota": "raw_quota"}), "offset": OffsetFilter(), "limit": LimitFilter(), } rateLimiterFilters = map[string]Filter{ "id": EqualFilter("id"), "pk": EqualFilter("id"), "squad_id_in": ExistsAndWhereInFilter( sqlbuilder.SQLite.NewSelectBuilder(). Select( "squad_id", ). Where( "rate_limiter_to_squad.rate_limiter_id = rate_limiters.id", ). From( "rate_limiter_to_squad", ), "rate_limiter_to_squad.squad_id", ), "strategy": EqualFilter("strategy"), "username": EqualFilter("username"), "outbound": EqualFilter("outbound"), "connection_type": EqualFilter("connection_type"), "interval": EqualFilter("interval"), "count_start": GreaterEqualThanFilter("count"), "count_end": LessEqualThanFilter("count"), "created_at_start": GreaterThanFilter("created_at"), "created_at_end": LessThanFilter("created_at"), "updated_at_start": GreaterThanFilter("updated_at"), "updated_at_end": LessThanFilter("updated_at"), "sort_asc": SortAscFilter(), "sort_desc": SortDescFilter(), "offset": OffsetFilter(), "limit": LimitFilter(), } }