Skip to content

Schema

In NimbusDB, a schema defines the structure of your data, including the types of data you can store and the rules for how that data is organized. A well-designed schema helps ensure data integrity and makes it easier to query and manage your data.

You can create a model without defining a schema, which allows you to store any type of data without restrictions. However, this approach may lead to data inconsistency and makes it harder to manage your data effectively.

// `schema` is an optional parameter when creating a model, placed after the `name` parameter
// If you don't provide a schema, the model will be created with an empty schema,
// which means you can store any data in the model without any restrictions
var model_no_schema = new NimbusDBModel("global", "items");

A schema is defined as an object where each key represents a column name and the value defines the rules for that column. The rules can be as simple as specifying a data type or as complex as defining constraints, validators, and default values.

// Here's an example of a simple schema definition for an 'items' model
var simple_schema = {
id: NIMBUSDB_DATA_TYPE.INTEGER,
name: NIMBUSDB_DATA_TYPE.STRING,
price: NIMBUSDB_DATA_TYPE.NUMBER
};
var model_with_schema = new NimbusDBModel("global", "items", simple_schema);
// You can define schema with union data types using arrays
var union_schema = {
id: NIMBUSDB_DATA_TYPE.INTEGER,
name: NIMBUSDB_DATA_TYPE.STRING,
price: [NIMBUSDB_DATA_TYPE.NUMBER, NIMBUSDB_DATA_TYPE.STRING] // price can be a number or a string
};
var model_with_union_schema = new NimbusDBModel("global", "items", union_schema);
// Alternatively, you can define the schema using the object format
var object_schema = {
id: {
type: NIMBUSDB_DATA_TYPE.INTEGER,
const: NIMBUSDB_CONSTRAINT.PRIMARY_KEY // `id` column is the primary key of the model
},
name: NIMBUSDB_DATA_TYPE.STRING,
price: {
type: [NIMBUSDB_DATA_TYPE.NUMBER, NIMBUSDB_DATA_TYPE.STRING]
}
};
var model_with_object_schema = new NimbusDBModel("global", "items", object_schema);

You can choose to use the simple one (directly using data types or arrays of data types) or the advanced one (using the object format to specify constraints, validators, and default values) based on your needs.

NimbusDB supports a variety of data types that you can use in your schema definitions, including primitive types like NUMBER, STRING, and BOOLEAN, as well as complex types like STRUCT, METHOD, and various asset types.

You can also define union data types using arrays, allowing a column to accept multiple types of data.

Constraints are rules that you can apply to your columns to enforce data integrity. For example, you can use the PRIMARY_KEY constraint to designate a column as the primary key of the model, or the UNIQUE constraint to ensure that all values in a column are unique.

Here’s an example of how to use constraints in your schema definition:

var schema_with_constraints = {
id: {
type: NIMBUSDB_DATA_TYPE.INTEGER,
const: NIMBUSDB_CONSTRAINT.PRIMARY_KEY // `id` column is the primary key of the model
},
name: {
type: NIMBUSDB_DATA_TYPE.STRING,
const: NIMBUSDB_CONSTRAINT.UNIQUE // name must be unique across the model
},
price: {
type: [NIMBUSDB_DATA_TYPE.NUMBER, NIMBUSDB_DATA_TYPE.STRING]
},
is_locked: {
type: NIMBUSDB_DATA_TYPE.BOOLEAN,
const: NIMBUSDB_CONSTRAINT.OPTIONAL // is_locked is an optional column
},
sprite: {
type: NIMBUSDB_DATA_TYPE.ASSET_SPRITE,
const: [NIMBUSDB_CONSTRAINT.OPTIONAL, NIMBUSDB_CONSTRAINT.UNIQUE] // sprite is an optional column and its value must be unique if provided
}
};

Validators are methods that you can define in your schema to validate the data before it’s set to a column. If the validator fails (returns false):

  • If a default_value is provided, the column will be set to the default value instead of the new value, or call the method to get the default value if it’s a method.
  • Otherwise, the operation will be aborted and the data will not be inserted/updated in the model.

Here’s an example of how to use validators and default values in your schema definition:

var object_schema = {
id: {
type: NIMBUSDB_DATA_TYPE.INTEGER,
const: NIMBUSDB_CONSTRAINT.PRIMARY_KEY
},
name: {
type: NIMBUSDB_DATA_TYPE.STRING,
validator: function(data, value) {
return string_length(value) > 0; // name must be a non-empty string
}
},
price: {
type: [NIMBUSDB_DATA_TYPE.NUMBER, NIMBUSDB_DATA_TYPE.STRING],
validator: function(data, value) {
return is_numeric(value) ? (value >= 0) : (is_string(value) && real(value) >= 0); // price must be non-negative
},
default_value: 0 // default price is 0 if the validator fails
// you can also use a method to get the default value, for example:
// default_value: function(data, value) {
// return 0; // default price is 0 if the validator fails
// }
},
is_locked: {
type: NIMBUSDB_DATA_TYPE.BOOLEAN,
const: NIMBUSDB_CONSTRAINT.OPTIONAL,
default_value: false // default is_locked is false if `is_locked` is not provided
}
};
var model_with_object_schema = new NimbusDBModel("global", "items", object_schema);

Model for NimbusDB that manages schema-backed data, relations, queries, and lifecycle operations.

model.d.ts
class NimbusDBModel {
constructor(
_root: Instance | "global",
_name: string,
_schema?: NimbusDBSchema,
_data?: Struct | Struct[],
_option?: NimbusDBModelOptions
);
cache: {
[key: number | string]: NimbusDBData;
};
custom_id: int;
data: NimbusDBData[];
debug: boolean | 2 | 3;
id: int;
name: string;
ref: { // exposed data
[key: string]: NimbusDBData;
};
primary_key?: string;
temp?: Struct; // temporary user data
static __id: int;
__root: Instance | "global";
__data_id: int;
__in_transaction: boolean;
__locked: boolean;
__column_names?: string[];
__relations: NimbusDBRelation[];
__schema?: NimbusDBSchema;
__sys_temp?: Struct; // temporary system data
// ...public and internal methods
}
model.d.ts
class NimbusDBModel {
constructor(
_root: Instance | "global",
_name: string,
_schema?: NimbusDBSchema,
_data?: Struct | Struct[],
_option?: NimbusDBModelOptions
)
}
  • Type: Instance | "global"
  • The root/place where the model is located. If the model is located in the global scope (e.g. global variable), you can use "global" as the value. Otherwise, you can provide an instance/object id of the root object where the model is located.
  • Type: string
  • The name of the model.
  • Type: NimbusDBSchema
  • Default: undefined
  • The schema (column rules) of the model. If not provided, the model will be created with an empty schema.
  • Type: Struct | Struct[]
  • Default: undefined
  • The initial data to be inserted into the model. If not provided, the model doesn’t have any data initially.
  • Type: NimbusDBModelOptions
  • Default: undefined
  • The options for the model. See the NimbusDBModelOptions type for the available options.

The schema is a type that defines the columns and their rules for a model. It is an object where the keys are the column names and the values are the column rules.

schema.d.ts
type NimbusDBSchema = {
[column_name: string]: NimbusDBColumnRules;
};

The column rules are used to define the type, constraints, and validation rules for a column in a model. It can be a single data type, an array of data types, or an object with additional options.

column_rules.d.ts
type NimbusDBColumnRules =
| NIMBUSDB_DATA_TYPE
| NIMBUSDB_DATA_TYPE[]
| {
type: NIMBUSDB_DATA_TYPE | NIMBUSDB_DATA_TYPE[];
const?: NIMBUSDB_CONSTRAINT | NIMBUSDB_CONSTRAINT[]; // `const` is used to specify constraints for the column
validator?: ( // a function that validates the value before it's set to the column
data: Struct, // new data (after calling the method if it's a method)
value: any, // new value
temp: Struct,
model: NimbusDBModel
) => boolean;
default_value?: any | (( // a default value or a function that returns a default value when the validator fails or when the value is not provided
data: Struct, // original data
value: any, // original value
temp: Struct,
model: NimbusDBModel
) => any);
}
;

The model options are used to configure the behavior of a model, such as column order, custom ID, debugging, and more.

model_options.d.ts
type NimbusDBModelOptions = Partial<{
column_order: string[]; // order of columns (default = undefined, use columns in the `column_names` property)
custom_id: int; // set custom ID (default = 0)
debug: boolean | 2 | 3; // enable debugging, true/1 = ~warning, 2 = ~success, 3 = ~info (default = false)
init_cache: boolean; // initialize cache for initial data (default = false)
in_tx: boolean; // [INTERNAL] whether the model is in a transaction (default = false)
force_insert: boolean; // force insertion of initial data (default = false)
start_id: int; // start ID for auto-increment (default = 1)
temp: Struct; // set temporary data (default = undefined)
}>;

The data types are used to define the type of data that can be stored in a column in a model. They can be used directly as the value of the type property in the column rules, or as an array of data types to allow a column to accept multiple types of data.

data_types.d.ts
enum NIMBUSDB_DATA_TYPE {
ANY,
NUMBER,
INTEGER,
STRING,
BOOLEAN,
STRUCT,
METHOD,
INSTANCE,
ASSET_OBJECT,
ASSET_SPRITE,
ASSET_SOUND,
ASSET_ROOM,
ASSET_TILES,
ASSET_PATH,
ASSET_FONT,
ASSET_SHADER,
ARRAY_ANY,
ARRAY_NUMBER,
ARRAY_INTEGER,
ARRAY_STRING,
ARRAY_BOOLEAN,
ARRAY_STRUCT,
ARRAY_METHOD,
ARRAY_INSTANCE,
ARRAY_ASSET_OBJECT,
ARRAY_ASSET_SPRITE,
ARRAY_ASSET_SOUND,
ARRAY_ASSET_ROOM,
ARRAY_ASSET_TILES,
ARRAY_ASSET_PATH,
ARRAY_ASSET_FONT,
ARRAY_ASSET_SHADER
}

The constraints are used to define the rules for a column in a model, such as whether it is optional, unique, or primary key.

constraints.d.ts
enum NIMBUSDB_CONSTRAINT {
NONE,
OPTIONAL,
UNIQUE,
PRIMARY_KEY
// NOT_NULL = set automatically when the column is defined with data type(s)
// CHECK = `validator` in the column rules
// DEFAULT = `default_value` in the column rules
// AUTO_INCREMENT = set automatically on a column with PRIMARY_KEY constraint
// FOREIGN_KEY = set automatically through `.define_relation()` method
}