-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
869 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package constant | ||
|
||
import "fmt" | ||
|
||
type Kind string | ||
|
||
const ( | ||
KIND_INT Kind = "int" | ||
KIND_STR Kind = "string" | ||
) | ||
|
||
// Const denotes values stored in the database. | ||
type Const struct { | ||
val any | ||
kind Kind | ||
} | ||
|
||
func NewConstant(kind Kind, val any) (*Const, error) { | ||
switch kind { | ||
case KIND_INT: | ||
if _, ok := val.(int); !ok { | ||
return nil, fmt.Errorf("constant: value is not an integer") | ||
} | ||
case KIND_STR: | ||
if _, ok := val.(string); !ok { | ||
return nil, fmt.Errorf("constant: value is not a string") | ||
} | ||
default: | ||
} | ||
return &Const{ | ||
val: val, | ||
kind: kind, | ||
}, nil | ||
} | ||
|
||
// AsInt returns the integer value of the constant. | ||
func (c *Const) AsInt() int { | ||
if c.kind == KIND_INT { | ||
return c.val.(int) | ||
} | ||
return 0 // or panic/error if you want to handle it strictly | ||
} | ||
|
||
// AsString returns the string value of the constant. | ||
func (c *Const) AsString() string { | ||
if c.kind == KIND_STR { | ||
return c.val.(string) | ||
} | ||
return "" // or panic/error if you want to handle it strictly | ||
} | ||
|
||
// Equals checks if two constants are equal. | ||
func (c *Const) Equals(other *Const) bool { | ||
if c.kind != other.kind { | ||
return false | ||
} | ||
return c.val == other.val | ||
} | ||
|
||
// CompareTo returns 0 if two constants are equal, -1 if the receiver is less than the other, and 1 if the receiver is greater than the other. | ||
func (c *Const) CompareTo(other *Const) int { | ||
if c.kind != other.kind { | ||
return 0 // or panic/error if you want to handle it strictly | ||
} | ||
if c.val == other.val { | ||
return 0 | ||
} | ||
// TODO: Implement comparison for other types | ||
if c.val.(int) < other.val.(int) { | ||
return -1 | ||
} | ||
return 1 | ||
} | ||
|
||
// HashCode returns the hash code of the constant. | ||
func (c *Const) HashCode() int { | ||
// TODO: Implement more valid hash code | ||
switch c.kind { | ||
case KIND_INT: | ||
return c.AsInt() | ||
case KIND_STR: | ||
return len(c.AsString()) | ||
} | ||
return 0 | ||
} | ||
|
||
// ToString returns the string representation of the constant. | ||
func (c *Const) ToString() string { | ||
switch c.kind { | ||
case KIND_INT: | ||
return fmt.Sprint(c.AsInt()) | ||
case KIND_STR: | ||
return c.AsString() | ||
} | ||
return "" | ||
} | ||
|
||
func (c *Const) Kind() Kind { | ||
return c.kind | ||
} | ||
|
||
func (c *Const) AnyValue() any { | ||
return c.val | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package constant | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestConstant(t *testing.T) { | ||
t.Run("NewConstant", func(t *testing.T) { | ||
c, _ := NewConstant(KIND_INT, 42) | ||
assert.Equal(t, 42, c.AsInt()) | ||
c, _ = NewConstant(KIND_STR, "hello") | ||
assert.Equal(t, "hello", c.AsString()) | ||
_, err := NewConstant(KIND_INT, "hello") | ||
assert.Error(t, err) | ||
}) | ||
t.Run("Equals", func(t *testing.T) { | ||
c1, _ := NewConstant(KIND_INT, 42) | ||
c2, _ := NewConstant(KIND_INT, 42) | ||
c3, _ := NewConstant(KIND_INT, 43) | ||
c4, _ := NewConstant(KIND_STR, "hello") | ||
assert.True(t, c1.Equals(c2)) | ||
assert.False(t, c1.Equals(c3)) | ||
assert.False(t, c1.Equals(c4)) | ||
}) | ||
t.Run("CompareTo", func(t *testing.T) { | ||
c1, _ := NewConstant(KIND_INT, 42) | ||
c2, _ := NewConstant(KIND_INT, 42) | ||
c3, _ := NewConstant(KIND_INT, 43) | ||
c4, _ := NewConstant(KIND_STR, "hello") | ||
assert.Equal(t, 0, c1.CompareTo(c2)) | ||
assert.Equal(t, -1, c1.CompareTo(c3)) | ||
assert.Equal(t, 1, c3.CompareTo(c1)) | ||
assert.Equal(t, 0, c4.CompareTo(c4)) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package query | ||
|
||
import ( | ||
"github.com/kj455/db/pkg/constant" | ||
"github.com/kj455/db/pkg/record" | ||
) | ||
|
||
// Expression corresponds to SQL expressions. | ||
type ExpressionImpl struct { | ||
val *constant.Const | ||
field string | ||
} | ||
|
||
// NewConstantExpression creates a new expression with a constant value. | ||
func NewConstantExpression(val *constant.Const) Expression { | ||
return &ExpressionImpl{val: val} | ||
} | ||
|
||
// NewFieldExpression creates a new expression with a field name. | ||
func NewFieldExpression(field string) Expression { | ||
return &ExpressionImpl{field: field} | ||
} | ||
|
||
// Evaluate evaluates the expression with respect to the current constant of the specified scan. | ||
func (e *ExpressionImpl) Evaluate(s Scan) (*constant.Const, error) { | ||
if e.val != nil { | ||
return e.val, nil | ||
} | ||
return s.GetVal(e.field) | ||
} | ||
|
||
// IsFieldName returns true if the expression is a field reference. | ||
func (e *ExpressionImpl) IsFieldName() bool { | ||
return e.field != "" | ||
} | ||
|
||
// AsConstant returns the constant corresponding to a constant expression, or nil if the expression does not denote a constant. | ||
func (e *ExpressionImpl) AsConstant() *constant.Const { | ||
return e.val | ||
} | ||
|
||
// AsFieldName returns the field name corresponding to a constant expression, or an empty string if the expression does not denote a field. | ||
func (e *ExpressionImpl) AsFieldName() string { | ||
return e.field | ||
} | ||
|
||
// AppliesTo determines if all of the fields mentioned in this expression are contained in the specified schema. | ||
func (e *ExpressionImpl) AppliesTo(sch record.Schema) bool { | ||
if e.val != nil { | ||
return true | ||
} | ||
return sch.HasField(e.field) | ||
} | ||
|
||
// ToString returns the string representation of the expression. | ||
func (e *ExpressionImpl) ToString() string { | ||
if e.val != nil { | ||
return e.val.ToString() | ||
} | ||
return e.field | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package query | ||
|
||
import ( | ||
"github.com/kj455/db/pkg/constant" | ||
"github.com/kj455/db/pkg/record" | ||
) | ||
|
||
type Scan interface { | ||
// BeforeFirst positions the scan before its first record. | ||
// A subsequent call to Next will return the first record. | ||
BeforeFirst() error | ||
|
||
// Next moves the scan to the next record. | ||
// Returns false if there is no next record. | ||
Next() bool | ||
|
||
// GetInt returns the value of the specified integer field in the current record. | ||
GetInt(field string) (int, error) | ||
|
||
// GetString returns the value of the specified string field in the current record. | ||
GetString(field string) (string, error) | ||
|
||
// GetVal returns the value of the specified field in the current record, expressed as a Constant. | ||
GetVal(field string) (*constant.Const, error) | ||
|
||
// HasField checks if the scan has the specified field. | ||
// The field parameter represents the name of the field. | ||
// Returns true if the scan has that field. | ||
HasField(field string) bool | ||
|
||
// Close closes the scan and its subscans, if any. | ||
Close() | ||
} | ||
|
||
type UpdateScan interface { | ||
Scan | ||
SetInt(field string, val int) error | ||
SetString(field string, val string) error | ||
SetVal(field string, val *constant.Const) error | ||
Insert() error | ||
Delete() error | ||
|
||
GetRID() record.RID | ||
MoveToRID(rid record.RID) error | ||
} | ||
|
||
type Predicate interface { | ||
IsSatisfied(s Scan) (bool, error) | ||
} | ||
|
||
type Expression interface { | ||
Evaluate(s Scan) (*constant.Const, error) | ||
IsFieldName() bool | ||
AsConstant() *constant.Const | ||
AsFieldName() string | ||
AppliesTo(sch record.Schema) bool | ||
ToString() string | ||
} | ||
|
||
type PlanInfo interface { | ||
DistinctValues(field string) int | ||
} |
Oops, something went wrong.