6bfc5b3a3c
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
- Pure Nim wire protocol client (async + sync, no C FFI) - Query Builder: fluent API, SQL generator, execution, transactions - Schema Builder: create/alter/drop tables, column operations - Connection pool with aging and timeout handling - ORM integration via compile-time DB_BARADB switch - Tests: test_open, test_query - Documentation: README.md, PLAN_BARADB.md
533 lines
38 KiB
Nim
533 lines
38 KiB
Nim
discard """
|
|
cmd: "nim c -d:reset $file"
|
|
"""
|
|
|
|
# nim c -r -d:reset -d:ssl tests/surrealdb/test_schema.nim
|
|
|
|
import std/unittest
|
|
import std/asyncdispatch
|
|
import std/json
|
|
import std/options
|
|
import std/strutils
|
|
import ../../src/allographer/schema_builder
|
|
import ../../src/allographer/query_builder
|
|
import ./connections
|
|
import ../clear_tables
|
|
|
|
|
|
proc normalizeInfoDef(s: string): string =
|
|
result = s
|
|
result = result.replace("`rand`::uuid()", "rand::uuid()")
|
|
result = result.replace("1.1f", "1.1")
|
|
result = result.replace("| none", "| NONE")
|
|
result = result.replace("| None", "| NONE")
|
|
result = result.replace(" PERMISSIONS FULL", "")
|
|
result = result.replace("{ key: 'value' }", "{\"key\":\"value\"}")
|
|
result = result.replace("{ key: \"value\" }", "{\"key\":\"value\"}")
|
|
result = result.replace("{key:'value'}", "{\"key\":\"value\"}")
|
|
|
|
|
|
proc `==`(a, b: string): bool =
|
|
cmp(normalizeInfoDef(a), normalizeInfoDef(b)) == 0
|
|
|
|
|
|
proc expectInfoEntries(node: JsonNode, entries: seq[tuple[key: string, expected: string]]) =
|
|
for entry in entries:
|
|
check normalizeInfoDef(node[entry.key].getStr()) == normalizeInfoDef(entry.expected)
|
|
|
|
|
|
suite("SurrealDB create table"):
|
|
test("create table"):
|
|
surreal.create(
|
|
table("relation", [
|
|
Column.uuid("uuid").unique(),
|
|
]),
|
|
table("TypeIndex", [
|
|
Column.increments("index"),
|
|
Column.integer("integer").unsigned().index().default(1),
|
|
Column.smallInteger("smallInteger").unsigned().index().default(1),
|
|
Column.mediumInteger("mediumInteger").unsigned().index().default(1),
|
|
Column.bigInteger("bigInteger").unsigned().index().default(1),
|
|
Column.decimal("decimal", 10, 3).unsigned().index().default(1.1),
|
|
Column.double("double", 10, 3).unsigned().index().default(1.1),
|
|
Column.float("float").unsigned().index().default(1.1),
|
|
Column.uuid("uuid").index().default("A"),
|
|
Column.char("char", 256).index().default("A"),
|
|
Column.string("string").index().default("A"),
|
|
Column.text("text").index().default("A"),
|
|
Column.mediumText("mediumText").index().default("A"),
|
|
Column.longText("longText").index().default("A"),
|
|
Column.date("date").index().default(),
|
|
Column.datetime("datetime1").index().default(Current),
|
|
Column.datetime("datetime2").index().default(CurrentOnUpdate),
|
|
Column.timestamp("timestamp").index().default(),
|
|
Column.timestamps(),
|
|
Column.softDelete(),
|
|
Column.binary("binary").index().default("A"),
|
|
Column.boolean("boolean").index().default(true),
|
|
Column.enumField("enumField", ["A", "B", "C"]).index().default("A"),
|
|
Column.json("json").index().default(%*{"key":"value"}),
|
|
Column.foreign("relation").reference("id").onTable("relation").onDelete(SET_NULL).nullable(),
|
|
]),
|
|
table("TypeUnique", [
|
|
Column.increments("index"),
|
|
Column.integer("integer").unsigned().index().unique().unique().default(1),
|
|
Column.smallInteger("smallInteger").unsigned().index().unique().unique().default(1),
|
|
Column.mediumInteger("mediumInteger").unsigned().index().unique().unique().default(1),
|
|
Column.bigInteger("bigInteger").unsigned().index().unique().unique().default(1),
|
|
Column.decimal("decimal", 10, 3).unsigned().index().unique().unique().default(1.1),
|
|
Column.double("double", 10, 3).unsigned().index().unique().unique().default(1.1),
|
|
Column.float("float").unsigned().index().unique().unique().default(1.1),
|
|
Column.uuid("uuid").index().unique().unique().default("A"),
|
|
Column.char("char", 256).index().unique().unique().default("A"),
|
|
Column.string("string").index().unique().unique().default("A"),
|
|
Column.text("text").index().unique().unique().default("A"),
|
|
Column.mediumText("mediumText").index().unique().unique().default("A"),
|
|
Column.longText("longText").index().unique().unique().default("A"),
|
|
Column.date("date").index().unique().unique().default(),
|
|
Column.datetime("datetime1").index().unique().unique().default(Current),
|
|
Column.datetime("datetime2").index().unique().unique().default(CurrentOnUpdate),
|
|
Column.timestamp("timestamp").index().unique().unique().default(),
|
|
Column.timestamps(),
|
|
Column.softDelete(),
|
|
Column.binary("binary").index().unique().unique().default("A"),
|
|
Column.boolean("boolean").index().unique().unique().default(true),
|
|
Column.enumField("enumField", ["A", "B", "C"]).index().unique().default("A"),
|
|
Column.json("json").index().unique().default(%*{"key":"value"}),
|
|
Column.foreign("relation").reference("id").onTable("relation").onDelete(SET_NULL).nullable(),
|
|
]),
|
|
)
|
|
|
|
block:
|
|
let info = surreal.raw(""" INFO FOR TABLE TypeIndex """).info().waitFor()
|
|
let resultNode = info[0]["result"]
|
|
let fields = resultNode["fields"]
|
|
expectInfoEntries(fields, @[
|
|
("index", "DEFINE FIELD index ON TypeIndex TYPE int VALUE $value OR (SELECT max_index FROM _autoincrement_sequences WHERE `table` = 'TypeIndex' AND column = 'index' LIMIT 1)[0].max_index + 1"),
|
|
("integer", "DEFINE FIELD integer ON TypeIndex TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("smallInteger", "DEFINE FIELD smallInteger ON TypeIndex TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("mediumInteger", "DEFINE FIELD mediumInteger ON TypeIndex TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("bigInteger", "DEFINE FIELD bigInteger ON TypeIndex TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("decimal", "DEFINE FIELD decimal ON TypeIndex TYPE decimal VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("double", "DEFINE FIELD double ON TypeIndex TYPE decimal VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("float", "DEFINE FIELD float ON TypeIndex TYPE float VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("uuid", "DEFINE FIELD uuid ON TypeIndex TYPE string VALUE $value OR rand::uuid() ASSERT $value != NONE"),
|
|
("char", "DEFINE FIELD char ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT string::len($value) < 256 AND $value != NONE"),
|
|
("string", "DEFINE FIELD string ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT string::len($value) < 256 AND $value != NONE"),
|
|
("text", "DEFINE FIELD text ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("mediumText", "DEFINE FIELD mediumText ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("longText", "DEFINE FIELD longText ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("date", "DEFINE FIELD date ON TypeIndex TYPE datetime VALUE $value OR <datetime> '1970-01-01T00:00:00Z' ASSERT $value != NONE"),
|
|
("datetime1", "DEFINE FIELD datetime1 ON TypeIndex TYPE datetime VALUE $value OR time::now() ASSERT $value != NONE"),
|
|
("datetime2", "DEFINE FIELD datetime2 ON TypeIndex TYPE datetime VALUE time::now() ASSERT $value != NONE"),
|
|
("timestamp", "DEFINE FIELD timestamp ON TypeIndex TYPE datetime VALUE $value OR <datetime> '1970-01-01T00:00:00Z' ASSERT $value != NONE"),
|
|
("created_at", "DEFINE FIELD created_at ON TypeIndex TYPE datetime VALUE $value OR time::now()"),
|
|
("updated_at", "DEFINE FIELD updated_at ON TypeIndex TYPE datetime VALUE time::now()"),
|
|
("deleted_at", "DEFINE FIELD deleted_at ON TypeIndex TYPE datetime"),
|
|
("binary", "DEFINE FIELD binary ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("boolean", "DEFINE FIELD boolean ON TypeIndex TYPE bool VALUE $value OR true ASSERT $value != NONE"),
|
|
("enumField", "DEFINE FIELD enumField ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value INSIDE ['A', 'B', 'C'] AND $value != NONE"),
|
|
("json", "DEFINE FIELD json ON TypeIndex TYPE object FLEXIBLE VALUE $value OR { key: 'value' } ASSERT $value != NONE"),
|
|
("relation", "DEFINE FIELD relation ON TypeIndex TYPE record<relation> | NONE VALUE $value OR NONE"),
|
|
])
|
|
|
|
let indexs = if resultNode.hasKey("indexes"): resultNode["indexes"] else: resultNode["ix"]
|
|
expectInfoEntries(indexs, @[
|
|
("TypeIndex_integer_index", "DEFINE INDEX TypeIndex_integer_index ON TypeIndex FIELDS integer"),
|
|
("TypeIndex_smallInteger_index", "DEFINE INDEX TypeIndex_smallInteger_index ON TypeIndex FIELDS smallInteger"),
|
|
("TypeIndex_mediumInteger_index", "DEFINE INDEX TypeIndex_mediumInteger_index ON TypeIndex FIELDS mediumInteger"),
|
|
("TypeIndex_bigInteger_index", "DEFINE INDEX TypeIndex_bigInteger_index ON TypeIndex FIELDS bigInteger"),
|
|
("TypeIndex_decimal_index", "DEFINE INDEX TypeIndex_decimal_index ON TypeIndex FIELDS decimal"),
|
|
("TypeIndex_double_index", "DEFINE INDEX TypeIndex_double_index ON TypeIndex FIELDS double"),
|
|
("TypeIndex_float_index", "DEFINE INDEX TypeIndex_float_index ON TypeIndex FIELDS float"),
|
|
("TypeIndex_uuid_unique", "DEFINE INDEX TypeIndex_uuid_unique ON TypeIndex FIELDS uuid UNIQUE"),
|
|
("TypeIndex_char_index", "DEFINE INDEX TypeIndex_char_index ON TypeIndex FIELDS char"),
|
|
("TypeIndex_string_index", "DEFINE INDEX TypeIndex_string_index ON TypeIndex FIELDS string"),
|
|
("TypeIndex_text_index", "DEFINE INDEX TypeIndex_text_index ON TypeIndex FIELDS text"),
|
|
("TypeIndex_mediumText_index", "DEFINE INDEX TypeIndex_mediumText_index ON TypeIndex FIELDS mediumText"),
|
|
("TypeIndex_longText_index", "DEFINE INDEX TypeIndex_longText_index ON TypeIndex FIELDS longText"),
|
|
("TypeIndex_date_index", "DEFINE INDEX TypeIndex_date_index ON TypeIndex FIELDS date"),
|
|
("TypeIndex_datetime1_index", "DEFINE INDEX TypeIndex_datetime1_index ON TypeIndex FIELDS datetime1"),
|
|
("TypeIndex_datetime2_index", "DEFINE INDEX TypeIndex_datetime2_index ON TypeIndex FIELDS datetime2"),
|
|
("TypeIndex_timestamp_index", "DEFINE INDEX TypeIndex_timestamp_index ON TypeIndex FIELDS timestamp"),
|
|
("TypeIndex_created_at_index", "DEFINE INDEX TypeIndex_created_at_index ON TypeIndex FIELDS created_at"),
|
|
("TypeIndex_updated_at_index", "DEFINE INDEX TypeIndex_updated_at_index ON TypeIndex FIELDS updated_at"),
|
|
("TypeIndex_deleted_at_index", "DEFINE INDEX TypeIndex_deleted_at_index ON TypeIndex FIELDS deleted_at"),
|
|
("TypeIndex_binary_index", "DEFINE INDEX TypeIndex_binary_index ON TypeIndex FIELDS binary"),
|
|
("TypeIndex_boolean_index", "DEFINE INDEX TypeIndex_boolean_index ON TypeIndex FIELDS boolean"),
|
|
("TypeIndex_enumField_index", "DEFINE INDEX TypeIndex_enumField_index ON TypeIndex FIELDS enumField"),
|
|
("TypeIndex_json_index", "DEFINE INDEX TypeIndex_json_index ON TypeIndex FIELDS json"),
|
|
])
|
|
|
|
block:
|
|
let info = surreal.raw(""" INFO FOR TABLE TypeUnique """).info().waitFor()
|
|
let resultNode = info[0]["result"]
|
|
let fields = resultNode["fields"]
|
|
expectInfoEntries(fields, @[
|
|
("index", "DEFINE FIELD index ON TypeUnique TYPE int VALUE $value OR (SELECT max_index FROM _autoincrement_sequences WHERE `table` = 'TypeUnique' AND column = 'index' LIMIT 1)[0].max_index + 1"),
|
|
("integer", "DEFINE FIELD integer ON TypeUnique TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("smallInteger", "DEFINE FIELD smallInteger ON TypeUnique TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("mediumInteger", "DEFINE FIELD mediumInteger ON TypeUnique TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("bigInteger", "DEFINE FIELD bigInteger ON TypeUnique TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("decimal", "DEFINE FIELD decimal ON TypeUnique TYPE decimal VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("double", "DEFINE FIELD double ON TypeUnique TYPE decimal VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("float", "DEFINE FIELD float ON TypeUnique TYPE float VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("uuid", "DEFINE FIELD uuid ON TypeUnique TYPE string VALUE $value OR rand::uuid() ASSERT $value != NONE"),
|
|
("char", "DEFINE FIELD char ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT string::len($value) < 256 AND $value != NONE"),
|
|
("string", "DEFINE FIELD string ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT string::len($value) < 256 AND $value != NONE"),
|
|
("text", "DEFINE FIELD text ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("mediumText", "DEFINE FIELD mediumText ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("longText", "DEFINE FIELD longText ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("date", "DEFINE FIELD date ON TypeUnique TYPE datetime VALUE $value OR <datetime> '1970-01-01T00:00:00Z' ASSERT $value != NONE"),
|
|
("datetime1", "DEFINE FIELD datetime1 ON TypeUnique TYPE datetime VALUE $value OR time::now() ASSERT $value != NONE"),
|
|
("datetime2", "DEFINE FIELD datetime2 ON TypeUnique TYPE datetime VALUE time::now() ASSERT $value != NONE"),
|
|
("timestamp", "DEFINE FIELD timestamp ON TypeUnique TYPE datetime VALUE $value OR <datetime> '1970-01-01T00:00:00Z' ASSERT $value != NONE"),
|
|
("created_at", "DEFINE FIELD created_at ON TypeUnique TYPE datetime VALUE $value OR time::now()"),
|
|
("updated_at", "DEFINE FIELD updated_at ON TypeUnique TYPE datetime VALUE time::now()"),
|
|
("deleted_at", "DEFINE FIELD deleted_at ON TypeUnique TYPE datetime"),
|
|
("binary", "DEFINE FIELD binary ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("boolean", "DEFINE FIELD boolean ON TypeUnique TYPE bool VALUE $value OR true ASSERT $value != NONE"),
|
|
("enumField", "DEFINE FIELD enumField ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value INSIDE ['A', 'B', 'C'] AND $value != NONE"),
|
|
("json", "DEFINE FIELD json ON TypeUnique TYPE object FLEXIBLE VALUE $value OR { key: 'value' } ASSERT $value != NONE"),
|
|
("relation", "DEFINE FIELD relation ON TypeUnique TYPE record<relation> | NONE VALUE $value OR NONE"),
|
|
])
|
|
|
|
let indexs = resultNode["indexes"]
|
|
expectInfoEntries(indexs, @[
|
|
("TypeUnique_integer_unique", "DEFINE INDEX TypeUnique_integer_unique ON TypeUnique FIELDS integer UNIQUE"),
|
|
("TypeUnique_smallInteger_unique", "DEFINE INDEX TypeUnique_smallInteger_unique ON TypeUnique FIELDS smallInteger UNIQUE"),
|
|
("TypeUnique_mediumInteger_unique", "DEFINE INDEX TypeUnique_mediumInteger_unique ON TypeUnique FIELDS mediumInteger UNIQUE"),
|
|
("TypeUnique_bigInteger_unique", "DEFINE INDEX TypeUnique_bigInteger_unique ON TypeUnique FIELDS bigInteger UNIQUE"),
|
|
("TypeUnique_decimal_unique", "DEFINE INDEX TypeUnique_decimal_unique ON TypeUnique FIELDS decimal UNIQUE"),
|
|
("TypeUnique_double_unique", "DEFINE INDEX TypeUnique_double_unique ON TypeUnique FIELDS double UNIQUE"),
|
|
("TypeUnique_float_unique", "DEFINE INDEX TypeUnique_float_unique ON TypeUnique FIELDS float UNIQUE"),
|
|
("TypeUnique_uuid_unique", "DEFINE INDEX TypeUnique_uuid_unique ON TypeUnique FIELDS uuid UNIQUE"),
|
|
("TypeUnique_char_unique", "DEFINE INDEX TypeUnique_char_unique ON TypeUnique FIELDS char UNIQUE"),
|
|
("TypeUnique_string_unique", "DEFINE INDEX TypeUnique_string_unique ON TypeUnique FIELDS string UNIQUE"),
|
|
("TypeUnique_text_unique", "DEFINE INDEX TypeUnique_text_unique ON TypeUnique FIELDS text UNIQUE"),
|
|
("TypeUnique_mediumText_unique", "DEFINE INDEX TypeUnique_mediumText_unique ON TypeUnique FIELDS mediumText UNIQUE"),
|
|
("TypeUnique_longText_unique", "DEFINE INDEX TypeUnique_longText_unique ON TypeUnique FIELDS longText UNIQUE"),
|
|
("TypeUnique_date_unique", "DEFINE INDEX TypeUnique_date_unique ON TypeUnique FIELDS date UNIQUE"),
|
|
("TypeUnique_datetime1_unique", "DEFINE INDEX TypeUnique_datetime1_unique ON TypeUnique FIELDS datetime1 UNIQUE"),
|
|
("TypeUnique_datetime2_unique", "DEFINE INDEX TypeUnique_datetime2_unique ON TypeUnique FIELDS datetime2 UNIQUE"),
|
|
("TypeUnique_timestamp_unique", "DEFINE INDEX TypeUnique_timestamp_unique ON TypeUnique FIELDS timestamp UNIQUE"),
|
|
("TypeUnique_created_at_index", "DEFINE INDEX TypeUnique_created_at_index ON TypeUnique FIELDS created_at"),
|
|
("TypeUnique_updated_at_index", "DEFINE INDEX TypeUnique_updated_at_index ON TypeUnique FIELDS updated_at"),
|
|
("TypeUnique_deleted_at_index", "DEFINE INDEX TypeUnique_deleted_at_index ON TypeUnique FIELDS deleted_at"),
|
|
("TypeUnique_binary_unique", "DEFINE INDEX TypeUnique_binary_unique ON TypeUnique FIELDS binary UNIQUE"),
|
|
("TypeUnique_boolean_unique", "DEFINE INDEX TypeUnique_boolean_unique ON TypeUnique FIELDS boolean UNIQUE"),
|
|
("TypeUnique_enumField_unique", "DEFINE INDEX TypeUnique_enumField_unique ON TypeUnique FIELDS enumField UNIQUE"),
|
|
("TypeUnique_json_unique", "DEFINE INDEX TypeUnique_json_unique ON TypeUnique FIELDS json UNIQUE"),
|
|
])
|
|
|
|
|
|
test("autoincrement"):
|
|
surreal.create(
|
|
table("test",[
|
|
Column.increments("index"),
|
|
Column.integer("index2").autoIncrement(),
|
|
Column.string("string")
|
|
])
|
|
)
|
|
|
|
surreal.table("test").insert(%*{"string": "a"}).waitFor
|
|
surreal.table("test").insert(%*{"string": "b"}).waitFor
|
|
surreal.table("test").insert(%*{"string": "c"}).waitFor
|
|
surreal.table("test").where("string", "=", "b").delete().waitFor
|
|
surreal.table("test").insert(%*{"string": "d"}).waitFor
|
|
|
|
let data = surreal.table("test").orderBy("index", Asc).get().waitFor
|
|
for row in data:
|
|
if row["string"].getStr == "a":
|
|
check row["index"].getInt == 1
|
|
check row["index2"].getInt == 1
|
|
|
|
if row["string"].getStr == "c":
|
|
check row["index"].getInt == 3
|
|
check row["index2"].getInt == 3
|
|
|
|
if row["string"].getStr == "d":
|
|
check row["index2"].getInt == 4
|
|
|
|
|
|
suite("Datetime"):
|
|
test("datetime default"):
|
|
surreal.create(
|
|
table("test", [
|
|
Column.string("name"),
|
|
Column.datetime("created_at").default(Current),
|
|
Column.datetime("updated_at").default(CurrentOnUpdate),
|
|
])
|
|
)
|
|
|
|
surreal.table("test").insert(%*{"name": "alice"}).waitFor()
|
|
|
|
var alice = surreal.table("test").first().waitFor().get()
|
|
let aliceId = SurrealId.new(alice["id"].getStr())
|
|
echo alice
|
|
let aliceCreatedAt1 = alice["created_at"].getStr()
|
|
let aliceUpdatedAt1 = alice["updated_at"].getStr()
|
|
|
|
surreal.table("test").where("id", "=", aliceId).update(%*{"name": "updated"}).waitFor()
|
|
|
|
alice = surreal.table("test").find(aliceId).waitFor().get()
|
|
echo alice
|
|
let aliceCreatedAt2 = alice["created_at"].getStr()
|
|
let aliceUpdatedAt2 = alice["updated_at"].getStr()
|
|
|
|
check aliceCreatedAt1 == aliceCreatedAt2
|
|
check aliceUpdatedAt1 != aliceUpdatedAt2
|
|
|
|
|
|
test("timestamps"):
|
|
surreal.create(
|
|
table("test", [
|
|
Column.string("name"),
|
|
Column.timestamps()
|
|
])
|
|
)
|
|
|
|
surreal.table("test").insert(%*{"name": "alice"}).waitFor()
|
|
|
|
var alice = surreal.table("test").first().waitFor().get()
|
|
let aliceId = SurrealId.new(alice["id"].getStr())
|
|
let aliceCreatedAt1 = alice["created_at"].getStr()
|
|
let aliceUpdatedAt1 = alice["updated_at"].getStr()
|
|
|
|
surreal.table("test").where("id", "=", aliceId).update(%*{"name": "updated"}).waitFor()
|
|
|
|
alice = surreal.table("test").find(aliceId).waitFor().get()
|
|
let aliceCreatedAt2 = alice["created_at"].getStr()
|
|
let aliceUpdatedAt2 = alice["updated_at"].getStr()
|
|
|
|
check aliceCreatedAt1 == aliceCreatedAt2
|
|
check aliceUpdatedAt1 != aliceUpdatedAt2
|
|
|
|
|
|
|
|
suite("SurrealDB alter table"):
|
|
setup:
|
|
surreal.create(
|
|
table("relation", [
|
|
Column.uuid("uuid").unique(),
|
|
]),
|
|
table("TypeUnique", [
|
|
Column.integer("num"),
|
|
Column.string("str"),
|
|
]),
|
|
table("TypeIndex", [
|
|
Column.integer("num"),
|
|
Column.string("str"),
|
|
])
|
|
)
|
|
|
|
|
|
test("add column"):
|
|
surreal.alter(
|
|
table("TypeIndex", [
|
|
Column.increments("index").add(),
|
|
Column.integer("integer").unsigned().index().default(1).add(),
|
|
Column.smallInteger("smallInteger").unsigned().index().default(1).add(),
|
|
Column.mediumInteger("mediumInteger").unsigned().index().default(1).add(),
|
|
Column.bigInteger("bigInteger").unsigned().index().default(1).add(),
|
|
Column.decimal("decimal", 10, 3).unsigned().index().default(1.1).add(),
|
|
Column.double("double", 10, 3).unsigned().index().default(1.1).add(),
|
|
Column.float("float").unsigned().index().default(1.1).add(),
|
|
Column.uuid("uuid").index().default("A").add(),
|
|
Column.char("char", 256).index().default("A").add(),
|
|
Column.string("string").index().default("A").add(),
|
|
Column.text("text").index().default("A").add(),
|
|
Column.mediumText("mediumText").index().default("A").add(),
|
|
Column.longText("longText").index().default("A").add(),
|
|
Column.date("date").index().default().add(),
|
|
Column.datetime("datetime1").index().default(Current).add(),
|
|
Column.datetime("datetime2").index().default(CurrentOnUpdate).add(),
|
|
Column.timestamp("timestamp").index().default().add(),
|
|
Column.timestamps().add(),
|
|
Column.softDelete().add(),
|
|
Column.binary("binary").index().default("A").add(),
|
|
Column.boolean("boolean").index().default(true).add(),
|
|
Column.enumField("enumField", ["A", "B", "C"]).index().default("A").add(),
|
|
Column.json("json").index().default(%*{"key":"value"}).add(),
|
|
Column.foreign("relation").reference("id").onTable("relation").onDelete(SET_NULL).nullable().add(),
|
|
]),
|
|
table("TypeUnique", [
|
|
Column.increments("index").add(),
|
|
Column.integer("integer").unsigned().index().unique().unique().default(1).add(),
|
|
Column.smallInteger("smallInteger").unsigned().index().unique().unique().default(1).add(),
|
|
Column.mediumInteger("mediumInteger").unsigned().index().unique().unique().default(1).add(),
|
|
Column.bigInteger("bigInteger").unsigned().index().unique().unique().default(1).add(),
|
|
Column.decimal("decimal", 10, 3).unsigned().index().unique().unique().default(1.1).add(),
|
|
Column.double("double", 10, 3).unsigned().index().unique().unique().default(1.1).add(),
|
|
Column.float("float").unsigned().index().unique().unique().default(1.1).add(),
|
|
Column.uuid("uuid").index().unique().unique().default("A").add(),
|
|
Column.char("char", 256).index().unique().unique().default("A").add(),
|
|
Column.string("string").index().unique().unique().default("A").add(),
|
|
Column.text("text").index().unique().unique().default("A").add(),
|
|
Column.mediumText("mediumText").index().unique().unique().default("A").add(),
|
|
Column.longText("longText").index().unique().unique().default("A").add(),
|
|
Column.date("date").index().unique().unique().default().add(),
|
|
Column.datetime("datetime1").index().unique().unique().default(Current).add(),
|
|
Column.datetime("datetime2").index().unique().unique().default(CurrentOnUpdate).add(),
|
|
Column.timestamp("timestamp").index().unique().unique().default().add(),
|
|
Column.timestamps().add(),
|
|
Column.softDelete().add(),
|
|
Column.binary("binary").index().unique().unique().default("A").add(),
|
|
Column.boolean("boolean").index().unique().unique().default(true).add(),
|
|
Column.enumField("enumField", ["A", "B", "C"]).index().unique().default("A").add(),
|
|
Column.json("json").index().unique().default(%*{"key":"value"}).add(),
|
|
Column.foreign("relation").reference("id").onTable("relation").onDelete(SET_NULL).nullable().add(),
|
|
]),
|
|
)
|
|
|
|
block:
|
|
let info = surreal.raw(""" INFO FOR TABLE TypeIndex """).info().waitFor()
|
|
let resultNode = info[0]["result"]
|
|
let fields = resultNode["fields"]
|
|
expectInfoEntries(fields, @[
|
|
("index", "DEFINE FIELD index ON TypeIndex TYPE int VALUE $value OR (SELECT max_index FROM _autoincrement_sequences WHERE `table` = 'TypeIndex' AND column = 'index' LIMIT 1)[0].max_index + 1"),
|
|
("integer", "DEFINE FIELD integer ON TypeIndex TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("smallInteger", "DEFINE FIELD smallInteger ON TypeIndex TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("mediumInteger", "DEFINE FIELD mediumInteger ON TypeIndex TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("bigInteger", "DEFINE FIELD bigInteger ON TypeIndex TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("decimal", "DEFINE FIELD decimal ON TypeIndex TYPE decimal VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("double", "DEFINE FIELD double ON TypeIndex TYPE decimal VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("float", "DEFINE FIELD float ON TypeIndex TYPE float VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("uuid", "DEFINE FIELD uuid ON TypeIndex TYPE string VALUE $value OR rand::uuid() ASSERT $value != NONE"),
|
|
("char", "DEFINE FIELD char ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT string::len($value) < 256 AND $value != NONE"),
|
|
("string", "DEFINE FIELD string ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT string::len($value) < 256 AND $value != NONE"),
|
|
("text", "DEFINE FIELD text ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("mediumText", "DEFINE FIELD mediumText ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("longText", "DEFINE FIELD longText ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("date", "DEFINE FIELD date ON TypeIndex TYPE datetime VALUE $value OR <datetime> '1970-01-01T00:00:00Z' ASSERT $value != NONE"),
|
|
("datetime1", "DEFINE FIELD datetime1 ON TypeIndex TYPE datetime VALUE $value OR time::now() ASSERT $value != NONE"),
|
|
("datetime2", "DEFINE FIELD datetime2 ON TypeIndex TYPE datetime VALUE time::now() ASSERT $value != NONE"),
|
|
("timestamp", "DEFINE FIELD timestamp ON TypeIndex TYPE datetime VALUE $value OR <datetime> '1970-01-01T00:00:00Z' ASSERT $value != NONE"),
|
|
("created_at", "DEFINE FIELD created_at ON TypeIndex TYPE datetime VALUE $value OR time::now()"),
|
|
("updated_at", "DEFINE FIELD updated_at ON TypeIndex TYPE datetime VALUE time::now()"),
|
|
("deleted_at", "DEFINE FIELD deleted_at ON TypeIndex TYPE datetime"),
|
|
("binary", "DEFINE FIELD binary ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("boolean", "DEFINE FIELD boolean ON TypeIndex TYPE bool VALUE $value OR true ASSERT $value != NONE"),
|
|
("enumField", "DEFINE FIELD enumField ON TypeIndex TYPE string VALUE $value OR 'A' ASSERT $value INSIDE ['A', 'B', 'C'] AND $value != NONE"),
|
|
("json", "DEFINE FIELD json ON TypeIndex TYPE object FLEXIBLE VALUE $value OR { key: 'value' } ASSERT $value != NONE"),
|
|
("relation", "DEFINE FIELD relation ON TypeIndex TYPE record<relation> | NONE VALUE $value OR NONE"),
|
|
])
|
|
|
|
let indexs = resultNode["indexes"]
|
|
expectInfoEntries(indexs, @[
|
|
("TypeIndex_integer_index", "DEFINE INDEX TypeIndex_integer_index ON TypeIndex FIELDS integer"),
|
|
("TypeIndex_smallInteger_index", "DEFINE INDEX TypeIndex_smallInteger_index ON TypeIndex FIELDS smallInteger"),
|
|
("TypeIndex_mediumInteger_index", "DEFINE INDEX TypeIndex_mediumInteger_index ON TypeIndex FIELDS mediumInteger"),
|
|
("TypeIndex_bigInteger_index", "DEFINE INDEX TypeIndex_bigInteger_index ON TypeIndex FIELDS bigInteger"),
|
|
("TypeIndex_decimal_index", "DEFINE INDEX TypeIndex_decimal_index ON TypeIndex FIELDS decimal"),
|
|
("TypeIndex_double_index", "DEFINE INDEX TypeIndex_double_index ON TypeIndex FIELDS double"),
|
|
("TypeIndex_float_index", "DEFINE INDEX TypeIndex_float_index ON TypeIndex FIELDS float"),
|
|
("TypeIndex_uuid_unique", "DEFINE INDEX TypeIndex_uuid_unique ON TypeIndex FIELDS uuid UNIQUE"),
|
|
("TypeIndex_char_index", "DEFINE INDEX TypeIndex_char_index ON TypeIndex FIELDS char"),
|
|
("TypeIndex_string_index", "DEFINE INDEX TypeIndex_string_index ON TypeIndex FIELDS string"),
|
|
("TypeIndex_text_index", "DEFINE INDEX TypeIndex_text_index ON TypeIndex FIELDS text"),
|
|
("TypeIndex_mediumText_index", "DEFINE INDEX TypeIndex_mediumText_index ON TypeIndex FIELDS mediumText"),
|
|
("TypeIndex_longText_index", "DEFINE INDEX TypeIndex_longText_index ON TypeIndex FIELDS longText"),
|
|
("TypeIndex_date_index", "DEFINE INDEX TypeIndex_date_index ON TypeIndex FIELDS date"),
|
|
("TypeIndex_datetime1_index", "DEFINE INDEX TypeIndex_datetime1_index ON TypeIndex FIELDS datetime1"),
|
|
("TypeIndex_datetime2_index", "DEFINE INDEX TypeIndex_datetime2_index ON TypeIndex FIELDS datetime2"),
|
|
("TypeIndex_timestamp_index", "DEFINE INDEX TypeIndex_timestamp_index ON TypeIndex FIELDS timestamp"),
|
|
("TypeIndex_created_at_index", "DEFINE INDEX TypeIndex_created_at_index ON TypeIndex FIELDS created_at"),
|
|
("TypeIndex_updated_at_index", "DEFINE INDEX TypeIndex_updated_at_index ON TypeIndex FIELDS updated_at"),
|
|
("TypeIndex_deleted_at_index", "DEFINE INDEX TypeIndex_deleted_at_index ON TypeIndex FIELDS deleted_at"),
|
|
("TypeIndex_binary_index", "DEFINE INDEX TypeIndex_binary_index ON TypeIndex FIELDS binary"),
|
|
("TypeIndex_boolean_index", "DEFINE INDEX TypeIndex_boolean_index ON TypeIndex FIELDS boolean"),
|
|
("TypeIndex_enumField_index", "DEFINE INDEX TypeIndex_enumField_index ON TypeIndex FIELDS enumField"),
|
|
("TypeIndex_json_index", "DEFINE INDEX TypeIndex_json_index ON TypeIndex FIELDS json"),
|
|
])
|
|
|
|
block:
|
|
let info = surreal.raw(""" INFO FOR TABLE TypeUnique """).info().waitFor()
|
|
let resultNode = info[0]["result"]
|
|
let fields = resultNode["fields"]
|
|
expectInfoEntries(fields, @[
|
|
("index", "DEFINE FIELD index ON TypeUnique TYPE int VALUE $value OR (SELECT max_index FROM _autoincrement_sequences WHERE `table` = 'TypeUnique' AND column = 'index' LIMIT 1)[0].max_index + 1"),
|
|
("integer", "DEFINE FIELD integer ON TypeUnique TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("smallInteger", "DEFINE FIELD smallInteger ON TypeUnique TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("mediumInteger", "DEFINE FIELD mediumInteger ON TypeUnique TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("bigInteger", "DEFINE FIELD bigInteger ON TypeUnique TYPE int VALUE $value OR 1 ASSERT $value != NONE AND $value >= 0"),
|
|
("decimal", "DEFINE FIELD decimal ON TypeUnique TYPE decimal VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("double", "DEFINE FIELD double ON TypeUnique TYPE decimal VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("float", "DEFINE FIELD float ON TypeUnique TYPE float VALUE $value OR 1.1 ASSERT $value != NONE AND $value >= 0"),
|
|
("uuid", "DEFINE FIELD uuid ON TypeUnique TYPE string VALUE $value OR rand::uuid() ASSERT $value != NONE"),
|
|
("char", "DEFINE FIELD char ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT string::len($value) < 256 AND $value != NONE"),
|
|
("string", "DEFINE FIELD string ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT string::len($value) < 256 AND $value != NONE"),
|
|
("text", "DEFINE FIELD text ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("mediumText", "DEFINE FIELD mediumText ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("longText", "DEFINE FIELD longText ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("date", "DEFINE FIELD date ON TypeUnique TYPE datetime VALUE $value OR <datetime> '1970-01-01T00:00:00Z' ASSERT $value != NONE"),
|
|
("datetime1", "DEFINE FIELD datetime1 ON TypeUnique TYPE datetime VALUE $value OR time::now() ASSERT $value != NONE"),
|
|
("datetime2", "DEFINE FIELD datetime2 ON TypeUnique TYPE datetime VALUE time::now() ASSERT $value != NONE"),
|
|
("timestamp", "DEFINE FIELD timestamp ON TypeUnique TYPE datetime VALUE $value OR <datetime> '1970-01-01T00:00:00Z' ASSERT $value != NONE"),
|
|
("created_at", "DEFINE FIELD created_at ON TypeUnique TYPE datetime VALUE $value OR time::now()"),
|
|
("updated_at", "DEFINE FIELD updated_at ON TypeUnique TYPE datetime VALUE time::now()"),
|
|
("deleted_at", "DEFINE FIELD deleted_at ON TypeUnique TYPE datetime"),
|
|
("binary", "DEFINE FIELD binary ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value != NONE"),
|
|
("boolean", "DEFINE FIELD boolean ON TypeUnique TYPE bool VALUE $value OR true ASSERT $value != NONE"),
|
|
("enumField", "DEFINE FIELD enumField ON TypeUnique TYPE string VALUE $value OR 'A' ASSERT $value INSIDE ['A', 'B', 'C'] AND $value != NONE"),
|
|
("json", "DEFINE FIELD json ON TypeUnique TYPE object FLEXIBLE VALUE $value OR { key: 'value' } ASSERT $value != NONE"),
|
|
("relation", "DEFINE FIELD relation ON TypeUnique TYPE record<relation> | NONE VALUE $value OR NONE"),
|
|
])
|
|
|
|
let indexs = if resultNode.hasKey("indexes"): resultNode["indexes"] else: resultNode["ix"]
|
|
expectInfoEntries(indexs, @[
|
|
("TypeUnique_integer_unique", "DEFINE INDEX TypeUnique_integer_unique ON TypeUnique FIELDS integer UNIQUE"),
|
|
("TypeUnique_smallInteger_unique", "DEFINE INDEX TypeUnique_smallInteger_unique ON TypeUnique FIELDS smallInteger UNIQUE"),
|
|
("TypeUnique_mediumInteger_unique", "DEFINE INDEX TypeUnique_mediumInteger_unique ON TypeUnique FIELDS mediumInteger UNIQUE"),
|
|
("TypeUnique_bigInteger_unique", "DEFINE INDEX TypeUnique_bigInteger_unique ON TypeUnique FIELDS bigInteger UNIQUE"),
|
|
("TypeUnique_decimal_unique", "DEFINE INDEX TypeUnique_decimal_unique ON TypeUnique FIELDS decimal UNIQUE"),
|
|
("TypeUnique_double_unique", "DEFINE INDEX TypeUnique_double_unique ON TypeUnique FIELDS double UNIQUE"),
|
|
("TypeUnique_float_unique", "DEFINE INDEX TypeUnique_float_unique ON TypeUnique FIELDS float UNIQUE"),
|
|
("TypeUnique_uuid_unique", "DEFINE INDEX TypeUnique_uuid_unique ON TypeUnique FIELDS uuid UNIQUE"),
|
|
("TypeUnique_char_unique", "DEFINE INDEX TypeUnique_char_unique ON TypeUnique FIELDS char UNIQUE"),
|
|
("TypeUnique_string_unique", "DEFINE INDEX TypeUnique_string_unique ON TypeUnique FIELDS string UNIQUE"),
|
|
("TypeUnique_text_unique", "DEFINE INDEX TypeUnique_text_unique ON TypeUnique FIELDS text UNIQUE"),
|
|
("TypeUnique_mediumText_unique", "DEFINE INDEX TypeUnique_mediumText_unique ON TypeUnique FIELDS mediumText UNIQUE"),
|
|
("TypeUnique_longText_unique", "DEFINE INDEX TypeUnique_longText_unique ON TypeUnique FIELDS longText UNIQUE"),
|
|
("TypeUnique_date_unique", "DEFINE INDEX TypeUnique_date_unique ON TypeUnique FIELDS date UNIQUE"),
|
|
("TypeUnique_datetime1_unique", "DEFINE INDEX TypeUnique_datetime1_unique ON TypeUnique FIELDS datetime1 UNIQUE"),
|
|
("TypeUnique_datetime2_unique", "DEFINE INDEX TypeUnique_datetime2_unique ON TypeUnique FIELDS datetime2 UNIQUE"),
|
|
("TypeUnique_timestamp_unique", "DEFINE INDEX TypeUnique_timestamp_unique ON TypeUnique FIELDS timestamp UNIQUE"),
|
|
("TypeUnique_created_at_index", "DEFINE INDEX TypeUnique_created_at_index ON TypeUnique FIELDS created_at"),
|
|
("TypeUnique_updated_at_index", "DEFINE INDEX TypeUnique_updated_at_index ON TypeUnique FIELDS updated_at"),
|
|
("TypeUnique_deleted_at_index", "DEFINE INDEX TypeUnique_deleted_at_index ON TypeUnique FIELDS deleted_at"),
|
|
("TypeUnique_binary_unique", "DEFINE INDEX TypeUnique_binary_unique ON TypeUnique FIELDS binary UNIQUE"),
|
|
("TypeUnique_boolean_unique", "DEFINE INDEX TypeUnique_boolean_unique ON TypeUnique FIELDS boolean UNIQUE"),
|
|
("TypeUnique_enumField_unique", "DEFINE INDEX TypeUnique_enumField_unique ON TypeUnique FIELDS enumField UNIQUE"),
|
|
("TypeUnique_json_unique", "DEFINE INDEX TypeUnique_json_unique ON TypeUnique FIELDS json UNIQUE"),
|
|
])
|
|
|
|
|
|
test("drop column"):
|
|
surreal.alter(
|
|
table("TypeIndex", [
|
|
Column.dropColumn("str")
|
|
])
|
|
)
|
|
|
|
let columns = surreal.table("TypeIndex").columns().waitFor
|
|
check not columns.contains("str")
|
|
|
|
|
|
test("drop table"):
|
|
surreal.create(
|
|
table("TypeIndex", [
|
|
Column.integer("num")
|
|
])
|
|
)
|
|
|
|
surreal.drop(
|
|
table("TypeIndex")
|
|
)
|
|
|
|
let res = surreal.table("TypeIndex").first().waitFor()
|
|
check not res.isSome
|
|
|
|
|
|
clearTables(surreal).waitFor()
|