Skip to content

Commit

Permalink
Added Usage table
Browse files Browse the repository at this point in the history
  • Loading branch information
svenefftinge authored and roboquat committed Sep 2, 2022
1 parent 81c5061 commit f54482b
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License-AGPL.txt in the project root for license information.
*/

import { MigrationInterface, QueryRunner } from "typeorm";

export class AddUsageTable1662040283793 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE \`d_b_usage\` (
\`id\` char(36) NOT NULL,
\`attributionId\` varchar(255) NOT NULL,
\`description\` varchar(255) NOT NULL,
\`creditCents\` bigint NOT NULL,
\`effectiveTime\` varchar(255) NOT NULL,
\`kind\` varchar(255) NOT NULL,
\`workspaceInstanceId\` char(36) NULL,
\`draft\` BOOLEAN NOT NULL,
\`metadata\` text NULL,
\`_created\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
\`_lastModified\` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
INDEX \`IDX_usage__attribution_id\` (\`attributionId\`),
INDEX \`IDX_usage__effectiveTime\` (\`effectiveTime\`),
INDEX \`IDX_usage__workspaceInstanceId\` (\`workspaceInstanceId\`),
INDEX \`IDX_usage___lastModified\` (\`_lastModified\`),
PRIMARY KEY (\`id\`)
) ENGINE=InnoDB`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX \`IDX_usage__attribution_id\` ON \`d_b_usage\``);
await queryRunner.query(`DROP INDEX \`IDX_usage__effectiveTime\` ON \`d_b_usage\``);
await queryRunner.query(`DROP INDEX \`IDX_usage__workspaceInstanceId\` ON \`d_b_usage\``);
await queryRunner.query(`DROP INDEX \`IDX_usage___lastModified\` ON \`d_b_usage\``);
await queryRunner.query(`DROP TABLE \`d_b_usage\``);
}
}
79 changes: 79 additions & 0 deletions components/usage/pkg/db/dbtest/usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.

package dbtest

import (
"testing"

"github.com/gitpod-io/gitpod/usage/pkg/db"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
)

func NewUsage(t *testing.T, record db.Usage) db.Usage {
t.Helper()

result := db.Usage{
ID: uuid.New(),
AttributionID: db.NewUserAttributionID(uuid.New().String()),
Description: "some description",
CreditCents: 42,
EffectiveTime: db.VarcharTime{},
Kind: "workspaceinstance",
WorkspaceInstanceID: uuid.New(),
}

if record.ID.ID() != 0 {
result.ID = record.ID
}
if record.EffectiveTime.IsSet() {
result.EffectiveTime = record.EffectiveTime
}
if record.AttributionID != "" {
result.AttributionID = record.AttributionID
}
if record.Description != "" {
result.Description = record.Description
}
if record.CreditCents != 0 {
result.CreditCents = record.CreditCents
}
if record.WorkspaceInstanceID.ID() != 0 {
result.WorkspaceInstanceID = record.WorkspaceInstanceID
}
if record.Kind != "" {
result.Kind = record.Kind
}
if record.Draft {
result.Draft = true
}
if record.Metadata != nil {
result.Metadata = record.Metadata
}
return result
}

func CreateUsageRecords(t *testing.T, conn *gorm.DB, entries ...db.Usage) []db.Usage {
t.Helper()

var records []db.Usage
var ids []string
for _, usageEntry := range entries {
record := NewUsage(t, usageEntry)
records = append(records, record)
ids = append(ids, record.ID.String())
}

require.NoError(t, conn.CreateInBatches(&records, 1000).Error)

t.Cleanup(func() {
require.NoError(t, conn.Where(ids).Delete(&db.Usage{}).Error)
})

t.Logf("stored %d", len(entries))

return records
}
53 changes: 53 additions & 0 deletions components/usage/pkg/db/usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.

package db

import (
"context"
"fmt"

"github.com/google/uuid"
"gorm.io/datatypes"
"gorm.io/gorm"
)

type Usage struct {
ID uuid.UUID `gorm:"primary_key;column:id;type:char;size:36;" json:"id"`
AttributionID AttributionID `gorm:"column:attributionId;type:varchar;size:255;" json:"attributionId"`
Description string `gorm:"column:description;type:varchar;size:255;" json:"description"`
CreditCents int64 `gorm:"column:creditCents;type:bigint;" json:"creditCents"`
EffectiveTime VarcharTime `gorm:"column:effectiveTime;type:varchar;size:255;" json:"effectiveTime"`
Kind string `gorm:"column:kind;type:char;size:10;" json:"kind"`
WorkspaceInstanceID uuid.UUID `gorm:"column:workspaceInstanceId;type:char;size:36;" json:"workspaceInstanceId"`
Draft bool `gorm:"column:draft;type:boolean;" json:"draft"`
Metadata datatypes.JSON `gorm:"column:metadata;type:text;size:65535" json:"metadata"`
}

type FindUsageResult struct {
UsageEntries []Usage
}

// TableName sets the insert table name for this struct type
func (u *Usage) TableName() string {
return "d_b_usage"
}

func FindUsage(ctx context.Context, conn *gorm.DB, attributionId AttributionID, from, to VarcharTime, offset int64, limit int64) ([]Usage, error) {
db := conn.WithContext(ctx)

var usageRecords []Usage
result := db.
WithContext(ctx).
Where("attributionId = ?", attributionId).
Where("? <= effectiveTime AND effectiveTime < ?", from.String(), to.String()).
Order("effectiveTime DESC").
Offset(int(offset)).
Limit(int(limit)).
Find(&usageRecords)
if result.Error != nil {
return nil, fmt.Errorf("failed to get usage records: %s", result.Error)
}
return usageRecords, nil
}
49 changes: 49 additions & 0 deletions components/usage/pkg/db/usage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.

package db_test

import (
"context"
"testing"
"time"

"github.com/gitpod-io/gitpod/usage/pkg/db"
"github.com/gitpod-io/gitpod/usage/pkg/db/dbtest"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)

func TestFindUsageInRange(t *testing.T) {
conn := dbtest.ConnectForTests(t)

start := time.Date(2022, 7, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2022, 8, 1, 0, 0, 0, 0, time.UTC)

attributionID := db.NewTeamAttributionID(uuid.New().String())

entryBefore := dbtest.NewUsage(t, db.Usage{
AttributionID: attributionID,
EffectiveTime: db.NewVarcharTime(start.Add(-1 * 23 * time.Hour)),
Draft: true,
})

entryInside := dbtest.NewUsage(t, db.Usage{
AttributionID: attributionID,
EffectiveTime: db.NewVarcharTime(start.Add(2 * time.Minute)),
})

entryAfter := dbtest.NewUsage(t, db.Usage{
AttributionID: attributionID,
EffectiveTime: db.NewVarcharTime(end.Add(2 * time.Hour)),
})

usageEntries := []db.Usage{entryBefore, entryInside, entryAfter}
dbtest.CreateUsageRecords(t, conn, usageEntries...)
listResult, err := db.FindUsage(context.Background(), conn, attributionID, db.NewVarcharTime(start), db.NewVarcharTime(end), 0, 10)
require.NoError(t, err)

require.Equal(t, 1, len(listResult))
require.Equal(t, []db.Usage{entryInside}, listResult)
}

0 comments on commit f54482b

Please sign in to comment.