Skip to content

Operations

DataSheetLang supports five operations for modifying entity data. Each operation serves a specific purpose in the data lifecycle.

Creates new entities. Fails if the entity ID already exists.

items:
create:
- id: 99001
name: "training_sword"
level: 1

Modifies existing entities by ID. Fails if the entity doesn’t exist.

items:
update:
- id: 99001
changes:
level: 10
buyPrice: 250

Removes entities by ID.

items:
delete:
- 99001
- 99002

Update-or-insert: creates the entity if it doesn’t exist, or updates it if it does. Useful for idempotent specs that work regardless of baseline state.

items:
upsert:
- id: 99001
name: "training_sword"
level: 1
category: Equipment
combatItemType: EquipWeapon

Key differences from create/update:

  • Uses the same structure as create (full entity data, not changes)
  • Does not fail if the entity already exists (unlike create)
  • Does not fail if the entity is missing (unlike update)
  • Running the same upsert twice produces identical results (idempotent)

Upsert supports inline blocks just like create:

items:
upsert:
- id: 99001
name: "iron_sword"
level: 60
equipment:
computed: true
compute:
formula: "standard"
strings:
name: "Iron Sword"
toolTip: "A basic training weapon."

Filter-based bulk updates modify all entities matching filter criteria without knowing specific IDs. Useful for batch modifications based on attributes.

items:
updateWhere:
- filter:
category: axe
requiredLevel: 60..70
changes:
sellPrice: 100

This updates sellPrice to 100 for all items where category is axe AND requiredLevel is between 60 and 70.

SyntaxYAML ExampleMeaning
Exact matchcategory: axecategory == "axe"
Range (inclusive)requiredLevel: 60..7060 <= requiredLevel <= 70
Multi-value (any-of)rareGrade: [0, 1, 2]rareGrade IN (0, 1, 2)
Flags includesrequiredClass: warriorrequiredClass includes warrior flag

Multiple filter keys use AND logic — all conditions must match:

items:
updateWhere:
- filter:
category: axe # AND
requiredLevel: 60..70 # AND
rareGrade: [0, 1] # all must match
changes:
sellPrice: 500

Multiple updateWhere rules are processed in order. Later rules override earlier rules for overlapping matches:

items:
updateWhere:
# First: all axes get sellPrice 100
- filter:
category: axe
changes:
sellPrice: 100
# Second: high-level items get sellPrice 500 (overrides first for overlap)
- filter:
requiredLevel: 60..70
changes:
sellPrice: 500

An item that is both an axe AND has requiredLevel 65 ends up with sellPrice: 500.

All schema attributes are filterable by default. For filter syntax by type, see Filters.

For the complete list of attributes available on each schema, see Schemas.

For flags enums like requiredClass, use includes to check if a specific flag is set:

items:
updateWhere:
- filter:
requiredClass: warrior # items usable by warrior class
changes:
sellPrice: 150
  • Ranges use .. separator: 60..70 means 60 to 70 inclusive
  • Quoted strings like "60..70" are treated as exact match, not range
  • Ranges work on numeric types (int, decimal)

Operations execute in a fixed order regardless of how they appear in the spec:

  1. create / upsert — new entities are added first (upsert also updates existing)
  2. updateWhere — bulk filter-based updates apply second
  3. update — explicit ID-based updates apply third
  4. delete — removals happen last

This ordering means explicit update operations act as an escape hatch after bulk updateWhere:

items:
updateWhere:
- filter:
category: axe
changes:
sellPrice: 100
update:
- id: 99001
changes:
sellPrice: 999 # overrides updateWhere for this specific item

Even though updateWhere sets all axes to sellPrice: 100, item 99001 ends up with sellPrice: 999 because update runs after updateWhere.

EntitycreateupdatedeleteupsertupdateWhere
Items
Equipment
ItemStrings
Quests
CCompensations